Spring中bean的生命周期(包括ApplicationContextAware,InitializingBean,PostProcessor示例)

本文参考:《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的一个应用:

实现InitializingBean接口,覆盖其afterPropertiesSet()方法,在实例化Consumer的bean实例之前调用其方法;此外,为了知道有哪些 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;
    }
}


猜你喜欢

转载自blog.csdn.net/u012156116/article/details/80623507