前言

Spring中@Autowired能够主动拆卸容器组件,默认按type注入,有多个雷同类型的bean时按name注入。此例为@Autowired的最简略实现,并不齐全正当,自己也是小白,大神轻喷。

思路

实现BeanPostProcessor接口能够对bean进行后置解决。通过反射,查找bean中有需主动拆卸字段,从容器中获取bean,并对其注入。

代码实现

1.pom

<dependencies>        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-context</artifactId>            <version>4.3.12.RELEASE</version>        </dependency>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>4.13.1</version>            <scope>test</scope>        </dependency>    </dependencies>

2.注解

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface AutoInject {}

3. 测试实体

public class School {    private String name;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    @Override    public String toString() {        return "School{" +                "name='" + name + '\'' +                '}';    }}public class Grade {    private String level;    @AutoInject    private School school;    public String getLevel() {        return level;    }    public void setLevel(String level) {        this.level = level;    }    public School getSchool() {        return school;    }    public void setSchool(School school) {        this.school = school;    }    @Override    public String toString() {        return "Grade{" +                "level='" + level + '\'' +                ", school=" + school +                '}';    }}public class Student {    private String name;    @AutoInject    private Grade grade;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Grade getGrade() {        return grade;    }    public void setGrade(Grade grade) {        this.grade = grade;    }    @Override    public String toString() {        return "Student{" +                "name='" + name + '\'' +                ", grade=" + grade +                '}';    }}

4. 后置处理器

@Componentpublic class AutoInjectProcessor implements BeanPostProcessor, ApplicationContextAware {    private ApplicationContext applicationContext;    @Override    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {        Field[] declaredFields = bean.getClass().getDeclaredFields();        for (Field declaredField : declaredFields) {//遍历字段查找须要主动注入的字段            AutoInject autoInject = declaredField.getAnnotation(AutoInject.class);            if(autoInject!=null){                Class<?> aClass = declaredField.getType();                Map<String, ?> beansOfType = applicationContext.getBeansOfType(aClass);//从容器中获取bean                Object injectBean;                if(beansOfType.keySet().size()==1){//如果只有一个匹配的bean                    injectBean=beansOfType.get(beansOfType.keySet().iterator().next());                }else {//多个bean则依照name匹配                    injectBean=beansOfType.get(declaredField.getName());                }                declaredField.setAccessible(true);                try {                    declaredField.set(bean,injectBean);                } catch (IllegalAccessException e) {                    e.printStackTrace();                }            }        }        return bean;    }    @Override    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {        return bean;    }    @Override    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {        this.applicationContext=applicationContext;    }}

5. 配置类
请留神@ComponentScan中的门路

@Configuration@ComponentScan("com.github.beta.bean.test")public class AutoInjectConfig {    @Bean    public Grade grade(){        Grade grade=new Grade();        grade.setLevel("一年级");        return grade;    }    @Bean    public Student zhangsan(){        Student student=new Student();        student.setName("张三");        return student;    }    @Bean    public School school(){        School school=new School();        school.setName("宁波大学科学技术学院");        return school;    }}

6.测试类

public class AutowiredTest {    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AutoInjectConfig.class);    @Test    public void autoInject(){        Student bean = applicationContext.getBean(Student.class);        System.out.println(bean);    }}

测试后果

"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\IntelliJ IDEA 2020.2.3\lib\idea_rt.jar=6122:D:\IntelliJ IDEA 2020.2.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\IntelliJ IDEA 2020.2.3\lib\idea_rt.jar;D:\IntelliJ IDEA 2020.2.3\plugins\junit\lib\junit5-rt.jar;D:\IntelliJ IDEA 2020.2.3\plugins\junit\lib\junit-rt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;E:\study\spring-ano\target\test-classes;E:\study\spring-ano\target\classes;E:\RepMaven\org\springframework\spring-context\4.3.12.RELEASE\spring-context-4.3.12.RELEASE.jar;E:\RepMaven\org\springframework\spring-aop\4.3.12.RELEASE\spring-aop-4.3.12.RELEASE.jar;E:\RepMaven\org\springframework\spring-beans\4.3.12.RELEASE\spring-beans-4.3.12.RELEASE.jar;E:\RepMaven\org\springframework\spring-core\4.3.12.RELEASE\spring-core-4.3.12.RELEASE.jar;E:\RepMaven\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;E:\RepMaven\org\springframework\spring-expression\4.3.12.RELEASE\spring-expression-4.3.12.RELEASE.jar;E:\RepMaven\junit\junit\4.13.1\junit-4.13.1.jar;E:\RepMaven\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.github.beta.AutowiredTest2,autoInject四月 22, 2021 5:03:15 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5cbc508c: startup date [Thu Apr 22 17:03:15 SGT 2021]; root of context hierarchyStudent{name='张三', grade=Grade{level='一年级', school=School{name='宁波大学科学技术学院'}}}Picked up _JAVA_OPTIONS: -Xms512m -Xmx1024mProcess finished with exit code 0