zoukankan      html  css  js  c++  java
  • 《玩转Spring》第二章 BeanPostProcessor扩展

    版权声明:本文为博主原创文章。未经博主同意不得转载。

    https://blog.csdn.net/shan9liang/article/details/34421141

    上一章。介绍了怎样扩展spring类实现自己主动读取配置文件

    这一章,我们介绍怎样通过实现BeanPostProcessor接口,对容器中的Bean做一层代理。来满足我们的个性化需求。


    一、基本原理

    我非常不想贴代码,显得太没水平。有时候自己的语言又非常空洞。不得不贴代码,感觉用代码来说明一件事反而更easy些。


    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    public class BeanPostPrcessorImpl implements BeanPostProcessor {
     
        // Bean 实例化之前运行该方法
        public Object postProcessBeforeInitialization(Object bean, String beanName)
               throws BeansException {
           System.out.println( beanName + "開始实例化");
           return bean;
        }
     
        // Bean 实例化之后运行该方法
        public Object postProcessAfterInitialization(Object bean, String beanName)
               throws BeansException {
           System.out.println( beanName + "实例化完毕");
           return bean;
        }
    }


    然后将这个BeanPostProcessor接口的实现配置到Spring的配置文件里就能够了:

    <bean class="com.jialin.spring.BeanPostPrcessorImpl"/>


    注意:

    1、BeanPostProcessor的作用域是容器级的,它仅仅和所在容器有关。

    2、BeanFactory和ApplicationContext对待bean后置处理器稍有不同。ApplicationContext会自己主动检測在配置文件里实现了BeanPostProcessor接口的全部bean,并把它们注冊为后置处理器。然后在容器创建bean的适当时候调用它。部署一个后置处理器同部署其它的bean并没有什么差别。

    而使用BeanFactory实现的时候。bean 后置处理器必须通过以下相似的代码显式地去注冊:

    BeanPostPrcessorImpl beanPostProcessor = new BeanPostPrcessorImpl();
    Resource resource = new FileSystemResource("applicationContext.xml");
    ConfigurableBeanFactory factory = new XmlBeanFactory(resource);
    factory.addBeanPostProcessor(beanPostProcessor);
    factory.getBean("beanName");


    二、应用

    好东西总要用起来

    1、利用BeanPostProcessor接口实现Bean的动态代理。

    2、自己主动注入Logging。用于记录日志。


    Logger注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target( {
            ElementType.FIELD
    })
    public @interface Logger {
    }
    
    package com.jialin.framework.annotation;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanInitializationException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    
    public class LogBeanPostProcessor implements BeanPostProcessor {
    
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                return bean;
            }
    
            public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
                List<Class<?>> clazzes = getAllClasses(bean);
    
                for (Class<?> clazz : clazzes) {
                    initializeLog(bean, clazz);
                }
    
                return bean;
            }
    
            /**
             * 取得指定bean的class以及全部父类的列表, 该列表排列顺序为从父类到当前类
             * @param bean
             * @return
             */
            private List<Class<?>> getAllClasses(Object bean) {
                Class<?

    extends Object> clazz = bean.getClass(); List<Class<?

    >> clazzes = new ArrayList<Class<?

    >>(); while (clazz != null) { clazzes.add(clazz); clazz = clazz.getSuperclass(); } Collections.reverse(clazzes); return clazzes; } /** * 对logger变量进行初始化 * * @param bean * @param clazz */ private void initializeLog(Object bean, Class<? extends Object> clazz) { Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (field.getAnnotation(Logger.class) == null) { continue; } if (!field.getType().isAssignableFrom(Log.class)) { continue; } field.setAccessible(true); try { field.set(bean, LogFactory.getLog(clazz)); } catch (Exception e) { throw new BeanInitializationException(String .format("初始化logger失败!bean=%s;field=%s", bean, field)); } } } }



    在Spring配置文件里。增加

         <!--配置依据注解,自己主动注入Log对象-->

        <bean id="logBeanPocessor" class="com.jialin.framework.annotation.LogBeanPostProcessor" lazy-init="false" />


    //实现代理的BeanPostProcessor的实例。当中注入上文介绍的log:
    import java.lang.reflect.Proxy;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    import org.apache.commons.logging.Log;
     
    public class ProxyBeanPostProcesser implements BeanPostProcessor {
        private Map map = new ConcurrentHashMap(100);
    
       //使用logger的注解来简化定义,并自己主动注入
    
        @Logger
        private static final Log log;
     
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            MyProxy proxy = new MyProxy();
     
            if (bean.toString().contains("Proxy")) {
                log.info(beanName + "为代理类,不进行再次代理!");
                return bean;
            }
    
    
            //……
            //能够加一些其它条件。过滤掉你不想代理的bean
            //……省略部分代码
    
    
            if (map.get(beanName) != null) {
                log.info(beanName + "已经代理过,不进行再次代理!");
                return map.get(beanName);
            }
            proxy.setObj(bean);
            proxy.setName(beanName);
            Class[] iterClass = bean.getClass().getInterfaces();
            if (iterClass.length > 0) {
                Object proxyO = Proxy.newProxyInstance(bean.getClass().getClassLoader(), iterClass, proxy);
                map.put(beanName, proxyO);
                return proxyO;
            } else {
                log.info(beanName + "必须实现接口才干被代理。");
                return bean;
            }
        }
     
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
     
    }
     
    
    
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import org.apache.commons.logging.Log;
    import sun.reflect.Reflection;
     
    //代理类Proxy。当中注入上文介绍的log:
    public class MyProxy implements InvocationHandler {
    
       //使用logger的注解来简化定义,并自己主动注入
    
        @Logger  
        private static final Log  log;
     
        private Object obj;
     
        private String name;
     
        public String getName() {
            return name;
        }
     
        public void setName(String name) {
            this.name = name;
        }
     
        public Object getObj() {
            return obj;
        }
     
        public void setObj(Object obj) {
            this.obj = obj;
        }
     
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            log.info("-------------------" + "bean 名称为【" + name + "】方法为【" + method.getName() + "】-------------"
                    + obj.getClass());
            return method.invoke(obj, args);
        }
     
        public void printDetail(String detail) {
            log.error(detail);
        }
     
    }
     


    在Spring配置文件里。增加


    <!--配置自己主动为Bean配置代理对象-->

    <bean id="proxyBeanPocessor" class="com.jialin.framework.proxy. ProxyBeanPostProcesser " />


    从上面的介绍不难看出,实现了BeanPostProcessor接口定制我们自己的Bean处理器能够在Spring容器初始化Bean的时候做我们想做的非常多事。

    Spring首先会使用自己的处理器。然后陆续使用我们的处理器,典型的装饰者模式,我们自己定义的处理器就是一个个详细的装饰者。


    在这里预告一下,兴许会出一个文章,教大家怎样《实现一个面向服务的IOC容器。不使用不论什么框架。纯j2se代码》


    这篇到这,下篇继续,敬请关注!谢谢


    贾琳   写于 2014-6-25 河北廊坊  多云              




                                



查看全文
  • 相关阅读:
    BZOJ 1391: [Ceoi2008]order
    BZOJ 4504: K个串
    2019 年百度之星·程序设计大赛
    POJ 2398 Toy Storage (二分 叉积)
    POJ 2318 TOYS (二分 叉积)
    HDU 6697 Closest Pair of Segments (计算几何 暴力)
    HDU 6695 Welcome Party (贪心)
    HDU 6693 Valentine's Day (概率)
    HDU 6590 Code (判断凸包相交)
    POJ 3805 Separate Points (判断凸包相交)
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/10727721.html
  • Copyright © 2011-2022 走看看