本文参考:《Spring in action》
Spring中bean的生命周期相对比较复杂,因为我们可以利用Spring提供的扩展点来自定义bean的创建过程。
下图展示了bean装载到Spring应用上下文中的一个典型的生命周期过程。
bean的后置处理器:
•
Bean
后置处理器允许在调用初始化方法前后对
Bean
进行额外的处理
.
•
Bean
后置处理器对
IOC
容器里的所有
Bean
实例逐一处理
,
而非单一实例
.
其典型应用是
:
检查
Bean
属性的正确性或根据特定的标准更改
Bean
的属性
.
•
对
Bean
后置处理器而言
,
需要实现 BeanPostProcessor
接口
.
在初始化方法被调用前后
,Spring
将 把
每个
Bean
实例分别传递给上述接口的以下两个方法
:
示例:
1. Car.java
public class Car { public Car(){ System.out.println("Car is constructor..."); } private String brand; public void setBrand(String brand){ System.out.println("set brand"); this.brand = brand; } public void init(){ System.out.println("init..."); } public void destroy(){ System.out.println("destroy..."); } }
2.MyBeanPostProcessor.java
public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object o, String s) throws BeansException { System.out.println("BeforeInitialization: "+o+":"+s); //进行检查 if("Car".equals(s)){ // 因为postProcessor是对所有的bean进行的操作 } return o; } @Override public Object postProcessAfterInitialization(Object o, String s) throws BeansException { System.out.println("AfterInitialization: "+o+":"+s); return o; } }
3. beans-cycle.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="car" class="com.nowcoder.cycleLife_postprocesser.Car" init-method="init" destroy-method="destroy"> <property name="brand" value="audi"/> </bean> <!-- 配置bean的后置处理器 使用方式: 实现接口BeanPostprocessor接口,并实现两个方法,第一个方法在init()之前被调用, 第二个在init()之后被调用 o: bean 实例本身 s:IOC容器中配置的bean的名字,相当于beanName 返回值:是实际上返回给用户的那个bean,注意:可以在以上两个方法中修改返回的bean,甚至返回一个新的bean --> <!-- 配置bean的后置处理器:不需要配置id,IOC容器自动识别是一个BeanPostProcessor --> <bean class="com.nowcoder.cycleLife_postprocesser.MyBeanPostProcessor"></bean> </beans>
4. main函数
public static void main(String[] args) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-cycle.xml"); Car car = (Car)ctx.getBean("car"); System.out.println(car); //关闭IOC容器 ctx.close(); }
5. 输出结果:
Car is constructor... set brand BeforeInitialization: com.nowcoder.cycleLife_postprocesser.Car@1500955a:car init... AfterInitialization: com.nowcoder.cycleLife_postprocesser.Car@1500955a:car com.nowcoder.cycleLife_postprocesser.Car@1500955a destroy...
问题1:后处理bean作用某一个目标类,还是所有目标类?
所有
问题2:如何只作用一个?
通过“参数2”beanName进行控制
补充:
- Factory hook(勾子) that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.
- spring提供工厂勾子,用于修改实例对象,可以生成代理对象,是AOP底层。
模拟
A a =new A();
a = B.before(a) --> 将a的实例对象传递给后处理bean,可以生成代理对象并返回。
a.init();
a = B.after(a);
a.addUser(); //生成代理对象,目的在目标方法前后执行(例如:开启事务、提交事务)
a.destroy()
实现此类:
public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("前方法 : " + beanName); return bean; } @Override public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException { System.out.println("后方法 : " + beanName); // bean 目标对象 // 生成 jdk 代理 return Proxy.newProxyInstance( MyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("------开启事务"); //执行目标方法 Object obj = method.invoke(bean, args); System.out.println("------提交事务"); return obj; }}); } }
ApplicationContextAware的一个应用:
EventHandler
,我们还需要实现
ApplicationContextAware
接口,通过setApplicationContext方法获取当前的applicationContext对象,看看当前注册的
EventHandler
, 通过每个
EventHandler
的getSupportEventTypes方法,来完成config 的注册。
@Service public class EventConsumer implements InitializingBean, ApplicationContextAware { private static final Logger logger = LoggerFactory.getLogger(EventConsumer.class); private Map<EventType, List<EventHandler>> config = new HashMap<EventType, List<EventHandler>>(); private ApplicationContext applicationContext; @Autowired JedisAdapter jedisAdapter; @Override public void afterPropertiesSet() throws Exception { Map<String, EventHandler> beans = applicationContext.getBeansOfType(EventHandler.class); if (beans != null) { for (Map.Entry<String, EventHandler> entry : beans.entrySet()) { List<EventType> eventTypes = entry.getValue().getSupportEventTypes(); for (EventType type : eventTypes) { if (!config.containsKey(type)) { config.put(type, new ArrayList<EventHandler>()); } config.get(type).add(entry.getValue()); } } } Thread thread = new Thread(new Runnable() { @Override public void run() { while(true) { String key = RedisKeyUtil.getEventQueueKey(); List<String> events = jedisAdapter.brpop(0, key); for (String message : events) { if (message.equals(key)) { continue; } EventModel eventModel = JSON.parseObject(message, EventModel.class); if (!config.containsKey(eventModel.getType())) { logger.error("不能识别的事件"); continue; } for (EventHandler handler : config.get(eventModel.getType())) { handler.doHandle(eventModel); } } } } }); thread.start(); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }