一:ApplicationContextAware接口
实现ApplicationContextAware接口,重写setApplicationContext方法,可以将spring容器上下文对象注入,
然后持有spring上下文对象,可以通过该对象获取spring容器中注册的任何bean实例。
/**
* @author Administrator
* 实现ApplicationContextAware接口,重写setApplicationContext方法,会注入
* spring上下文对象,可以在程序中持有一个context的对象,通过context,我们可以获取任何
* spring容器管理的bean
*/
public class ApplicationContextUtils implements ApplicationContextAware{
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
ApplicationContextUtils.context = context;
}
public static ApplicationContext getApplicationContext(){
return context;
}
/**
* 通过beanName获取实例bean
* @param beanName
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String beanName){
return (T) context.getBean(beanName);
}
/**
* 通过类型获取实例bean,但是如果在spring容器中通过相同的类
* 的不同构造器创建两个不同的对象,通过类型则获取不到对象
* @param clazz
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(Class<?> clazz){
return (T) context.getBean(clazz);
}
}
测试两种获取实例bean的方式:
@Test
public void testAppContext() {
String conf = "applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(conf);
Emp emp = ApplicationContextUtils.getBean("emp");
System.out.println(emp);
Emp emp2 = ApplicationContextUtils.getBean(Emp.class);
System.out.println(emp2);
}
Emp [name=null, age=null, salary=null]
Emp [name=null, age=null, salary=null]
可以获取对象,但是如果xml中注册两个相同类型的bean,就会出问题:
<!-- 实例化对象,默认调用无参数构造器 -->
<bean id="emp" class="com.hlcui.entity.Emp" init-method="init"></bean>
<!-- 实例化对象,有参数构造器 -->
<bean id="emp2" class="com.hlcui.entity.Emp">
<property name="name" value="Tom"></property>
<property name="age" value="12"></property>
<property name="salary" value="14000.0"></property>
</bean>
实现ApplicationContextAware接口的同时,还要将类 ApplicationContextUtils 交给spring容器管理,这样在
spring容器启动的时候才会将该对象注册,当检测到该类实现该接口时,会把spring上下文对象注入。
下面看一下接口源码:
public interface ApplicationContextAware
extends Aware
{
public abstract void setApplicationContext(ApplicationContext applicationcontext)
throws BeansException;
}
ApplicationContextAware接口内部只有一个抽象方法setApplicationContext(),同时又继承Aware接口
Aware接口:
public interface Aware
{
}
空接口,就是一个标记
二:InitializingBean接口
实现该接口的类,需要重写 afterPropertiesSet() ,在实例化的时候,调用完构造方法创建对象之后,会调用
该方法执行一个初始化bean的动作,作用类似@PostContrcut注解和xml中配置的init-method属性,但是执行顺序
有区别
/**
* @author Administrator
* 员工Emp类,实现InitializingBean接口,重写afterPropertiesSet方法,还有注解@PostConstruct,同时还有
* 在实例化Emp的时候,配置了init-method="init"属性
*/
public class Emp implements InitializingBean{
private String name;
private Integer age;
private Double salary;
public Emp(){
System.out.println("constructor...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean...afterPropertiesSet");
}
@PostConstruct
public void reload(){
System.out.println("@PostConstruct");
}
public void init(){
System.out.println("method-init");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Emp [name=" + name + ", age=" + age + ", salary=" + salary + "]";
}
}
spring容器xml中配置:
<!-- 该配置扫描注解到spring容器 -->
<context:annotation-config/>
<bean id="applicationContextUtils" class="com.hlcui.util.ApplicationContextUtils"></bean>
<!-- 实例化对象,默认调用无参数构造器 -->
<bean id="emp" class="com.hlcui.entity.Emp" init-method="init"></bean>
<!-- 实例化对象,有参数构造器 -->
<bean id="emp2" class="com.hlcui.entity.Emp">
<property name="name" value="Tom"></property>
<property name="age" value="12"></property>
<property name="salary" value="14000.0"></property>
</bean>
<context:annotation-config/> 的作用是扫描注解到spring容器,但是它的作用有限制,不能用作扫描service,controller,component等
组件注册到spring,例如:<context:component-scan = "com.hlcui.*"/> 它的作用是扫描组件,包括上面的配置。
执行结果如下:
constructor...
@PostConstruct
InitializingBean...afterPropertiesSet
method-init
constructor...
@PostConstruct
InitializingBean...afterPropertiesSet
首先执行第一条:
<bean id="emp" class="com.hlcui.entity.Emp" init-method="init"></bean>
1:执行构造器,创建对象
2:创建对象之后,调用有@PostContruct注解的方法初始化bean对象
3:调用afterProptertiesSeet方法初始化对象
4:调用xml中配置的init-method方法初始化对象
执行第2条语句:
<bean id="emp2" class="com.hlcui.entity.Emp">
<property name="name" value="Tom"></property>
<property name="age" value="12"></property>
<property name="salary" value="14000.0"></property>
</bean>
1:执行构造器,创建对象
2:创建对象之后,调用有@PostContruct注解的方法初始化bean对象
3:调用afterProptertiesSeet方法初始化对象
这里创建完对象之后,有一个set注入的过程,会调用Emp类中的set*方法,对对象进行初始化,然后
在调用2,3步骤。
假如把Emp对象中set方法注释,那么第2条语句执行完创建对象之后,就会停止。
三:注入List<接口> 对象
如果在一个类里面需要依赖多个bean对象时,可以通过实现接口的方式,将所有的bean注入,方式如下:
/**
* @author Administrator
* IBusinessService接口是一个空接口,作为一个标记
*/
public interface IBusinessService {
public abstract void execute();
}
/**
* @author Administrator
*
*/
@Component
public class ABusinessServiceImpl implements IBusinessService{
@Override
public void execute() {
System.out.println("ABusinessServiceImpl...");
}
}
@Component
public class BBusinessServiceImpl implements IBusinessService{
@Override
public void execute() {
System.out.println("BBusinessServiceImpl...");
}
}
@Component
public class CBusinessServiceImpl implements IBusinessService{
@Override
public void execute() {
System.out.println("CBusinessServiceImpl...");
}
}
在*handler类中依赖上面3个类
@Component
public class BusinessServiceHandler {
@Autowired
private List<IBusinessService> services;
public void handler(){
for(IBusinessService s:services){
s.execute();
}
}
}
测试注入效果:
@Test
public void testAppContext() {
String conf = "applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(conf);
BusinessServiceHandler bhandler = ApplicationContextUtils.getBean("businessServiceHandler");
bhandler.handler();
}
ABusinessServiceImpl...
BBusinessServiceImpl...
CBusinessServiceImpl...
执行成功!