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 河北廊坊  多云              




                                



查看全文
  • 相关阅读:
    JAVA变量的作用域
    SQLite
    ajax
    浏览器调试
    SQL链接
    Computer
    Sql知识点总结
    Web Socket
    秒杀
    副业
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/10727721.html
  • Copyright © 2011-2022 走看看