前言
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