Chapter 06 - @Autowire 及 Aware
Section 01 - @Autowire的位置
@Autowire出了可以放在属性上,还可以放置的setter方法上以及有参构造方法上,都可以实现Bean的自动装配
@Autowire在Setter方法上首先给两个实体类增加@Component注解,给User增加一个Address的属性
@Component public class User { private String username; private String password; private Address address; public User() { System.out.println("User 无参数构造方法被调用"); } public Address getAddress() { return address; } @Autowired public void setAddress(Address address) { this.address = address; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "username='" + username + ''' + ", password='" + password + ''' + ", address=" + address + '}'; } } 复制代码
@Component public class Address { private Integer id; private String addressDetail; public Address() { System.out.println("Address空参构造方法被调用"); } public Address(Integer id, String addressDetail) { System.out.println("Address有参数构造方法被调用"); this.id = id; this.addressDetail = addressDetail; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getAddressDetail() { return addressDetail; } public void setAddressDetail(String addressDetail) { this.addressDetail = addressDetail; } @PostConstruct public void init(){ System.out.println("Address Bean 的初始化方法"); } @PreDestroy public void destroy(){ System.out.println("Address Bean的销毁方法"); } } 复制代码
在BeanAutoAssembleConfig配置扫描entity包,将User和Address注册到容器中
@ComponentScan(basePackages = {"com.citi.dao","com.citi.service","com.citi.controller","com.citi.entity"}) public class BeanAutoAssembleConfig { //@Primary @Bean("personDao2") public PersonDao personDao(){ return new PersonDao(); } } 复制代码
修改BeanAutoAssembleConfigTest,执行测试
public class BeanAutoAssembleConfitTest { @Test public void isSameBean(){ ApplicationContext context = new AnnotationConfigApplicationContext(BeanAutoAssembleConfig.class); System.out.println("IoC容器初始化完成"); Address address = context.getBean("address",Address.class); System.out.println(address); User user = context.getBean("user", User.class); System.out.println(user.getAddress()); // 关闭容器 ((AnnotationConfigApplicationContext)context).close(); } } 复制代码
执行测试,控制台打印,Address可以成功注入到User中
@Autowire在有参数的构造方法上新增加一个只包含Address参数的User构造方法,在方法上面增加@Autowire注解,同时将Setter方法的@Autowire注解注释
@Component public class User { private String username; private String password; private Address address; public User() { System.out.println("User 无参数构造方法被调用"); } @Autowired public User(Address address) { System.out.println("User有参数构造方法被调用"); this.address = address; } public Address getAddress() { return address; } //@Autowired public void setAddress(Address address) { this.address = address; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "username='" + username + ''' + ", password='" + password + ''' + ", address=" + address + '}'; } } 复制代码
其他地方不用修改,执行测试类,控制台打印如下,可以成功装配Bean,并且是通过调用User的Setter方法实现的
参考@Autowire源码,@Autowire注解可以放在构造方法,setter方法,属性及方法的参数上
Section 02 - Spring的Aware接口
修改entity包中的Product实体类,实现ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware接口,并实现接口中的方法
@Component public class Product implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware { private Integer id; private String name; private Integer price; private ApplicationContext applicationContext; @Override public void setBeanName(String name) { System.out.println("beanName为:" + name); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("IoC容器为:" + applicationContext); } @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { String result = resolver.resolveStringValue("操作系统为:${os.name}"); System.out.println(result); } // 省略getter/setter/toString方法 } 复制代码
在config包中增加一个配置类BeanAwareConfig,使用@ComponentScan将entity包中的类注册到容器中
@Configuration @ComponentScan(value = {"com.citi.entity"}) public class BeanAwareConfig { } 复制代码
在test包中增加一个测试类
public class BeanAwareConfigTest { @Test public void testAware(){ ApplicationContext context = new AnnotationConfigApplicationContext(BeanAutoAssembleConfig.class); System.out.println("IoC容器初始化完成"); Product product = context.getBean("product", Product.class); System.out.println(product); // 关闭容器 ((AnnotationConfigApplicationContext)context).close(); } } 复制代码
执行测试,控制台输出如下
控制台输出了IoC容器,beanName等信息,这些都是Spring 底层组件提供的 ,也就是说如果想要把Spring底层的组件注入到自定义的Bean中,需要实现相应的Aware接口,如ApplicationContextAware可以提供IoC容器,这些Aware类都是相关的Processor的后置处理器来处理。