前言
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. 后置处理器
@Component
public 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 hierarchy
Student{name='张三', grade=Grade{level='一年级', school=School{name='宁波大学科学技术学院'}}}
Picked up _JAVA_OPTIONS: -Xms512m -Xmx1024m
Process finished with exit code 0
发表回复