一 ApplicationContextAware
当一个类实现了这个接口(ApplicationContextAware)之后,这个类就可以方便获得ApplicationContext中的所有bean。换句话说,就是这个类可以直接获取spring配置文件中,所有有引用到的bean对象。
如果读过源码,就会发现BeanFactory中其实保存了Spring Bean容器中的属性,但是BeanFactory是一个接口且不对外暴露,真正暴露的其实是ApplicationContext,应为ApplicationContext中有一个
getAutowireCapableBeanFactory方法,返回
AutowireCapableBeanFactory接口,而AutowireCapableBeanFactory接口继承了BeanFactory接口。
@Service
public class ExcelOutYardManager implements ApplicationContextAware {
Map<String,IExcelOutYard> excelOutYardMap;
private Map<String, IExcelOutYard> getExcelOutYard() {
if (excelOutYardMap == null) {
excelOutYardMap = new HashMap<String, IExcelOutYard>();
}
return excelOutYardMap;
}
public IExcelOutYard getImpleService(String messageType){
return excelOutYardMap.get(messageType);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, IExcelOutYard> beansOfType = applicationContext.getBeansOfType(IExcelOutYard.class);
this.getExcelOutYard();
for (IExcelOutYard iExcelOutYard:beansOfType.values()) {
excelOutYardMap.put(iExcelOutYard.messageType(),iExcelOutYard);
}
}
}
二 InitializingBean接口
InitializingBean接口为bean提供了初始化方法的方式,只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候会执行该方法。一般用这个接口在Spring初始化bean之后做一些初始化操作。
这个特性比较多的运用在应用启动的时候设定自动执行的方法,比如应用启动时,从数据库查询出数据,放入对象
@Service
public class EdiInitializingService implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
-----
三 BeanPostProcessor接口
在Spring容器中完成bean实例化、配置以及其它初始化方法前后要添加一些特殊的处理逻辑。需要定义一个或多个BeanPostProcessor接口实现类,然后注册到Spring IOC容器中。
下面这个例子就是根据自定义注解拦截要注入的接口实现类,运用java反射和代理的知识点来进行有效的实现类注入。
public interface HelloService {
public void sayHello();
}
@Service
public class HelloServiceImpl1 implements HelloService{
@Override
public void sayHello() {
System.out.println("你好我是HelloServiceImpl1");
}
}
@Service
public class HelloServiceImpl2 implements HelloService{
@Override
public void sayHello() {
System.out.println("你好我是HelloServiceImpl2");
}
}
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RountingInjected {
String value() default "helloServiceImpl1";
}
@Component
public class HelloServiceInjectProcessor implements BeanPostProcessor {
@Autowired
private ApplicationContext applicationContext;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<?> targetCls = bean.getClass();
Field[] targetFld = targetCls.getDeclaredFields();
for (Field field : targetFld) {
//找到制定目标的注解类
if (field.isAnnotationPresent(RountingInjected.class)) {
if (!field.getType().isInterface()) {
throw new BeanCreationException("RoutingInjected field must be declared as an interface:" + field.getName()
+ " @Class " + targetCls.getName());
}
try {
this.handleRoutingInjected(field, bean, field.getType());
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return bean;
}
/**
* @param field
* @param bean
* @param type
* @throws IllegalAccessException
*/
private void handleRoutingInjected(Field field, Object bean, Class type) throws IllegalAccessException {
Map<String, Object> candidates = this.applicationContext.getBeansOfType(type);
field.setAccessible(true);
if (candidates.size() == 1) {
field.set(bean, candidates.values().iterator().next());
} else if (candidates.size() == 2) {
String injectVal = field.getAnnotation(RountingInjected.class).value();
Object proxy = RoutingBeanProxyFactory.createProxy(injectVal, type, candidates);
field.set(bean, proxy);
} else {
throw new IllegalArgumentException("Find more than 2 beans for type: " + type);
}
}
}
public class RoutingBeanProxyFactory {
private final static String DEFAULT_BEAN_NAME = "helloServiceImpl1";
public static Object createProxy(String name, Class type, Map<String, Object> candidates) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(type);
proxyFactory.addAdvice(new VersionRoutingMethodInterceptor(name, candidates));
return proxyFactory.getProxy();
}
static class VersionRoutingMethodInterceptor implements MethodInterceptor {
private Object targetObject;
public VersionRoutingMethodInterceptor(String name, Map<String, Object> beans) {
this.targetObject = beans.get(name);
if (this.targetObject == null) {
this.targetObject = beans.get(DEFAULT_BEAN_NAME);
}
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
return invocation.getMethod().invoke(this.targetObject, invocation.getArguments());
}
}
}
@Component
public class HelloServiceTest {
@RountingInjected(value = "helloServiceImpl2")
private HelloService helloService;
public void testSayHello() {
helloService.sayHello();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("colin.spring.basic.advanced.bbp");
HelloServiceTest helloServiceTest = applicationContext.getBean(HelloServiceTest.class);
helloServiceTest.testSayHello();
}
}
四 DisposableBean接口
Spring bean被销毁时调用,这个使用较少,但也是生命周期的一部分
五 Spring生命周期图
六 结语
如果和spring生命周期图对照,那么可以看到,每一个接口的实现就是spring生命周期的一部分,这些接口实际上也体现了Spring框架的灵活性,理解这些接口对spring框架的使用有极大的帮助。