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

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

                            

《玩转Spring》第二章 BeanPostProcessor扩展的更多相关文章

  1. Spring 3.x 实践 第一个例子(Spring 3.x 企业应用开发实战读书笔记第二章)

    前言:工作之后一直在搞android,现在需要更多和后台的人员交涉,技术栈不一样,难免鸡同鸭讲,所以稍稍学习下. 这个例子取自于<Spring 3.x 企业应用开发实战>一书中的第二章,I ...

  2. #Spring实战第二章学习笔记————装配Bean

    Spring实战第二章学习笔记----装配Bean 创建应用对象之间协作关系的行为通常称为装配(wiring).这也是依赖注入(DI)的本质. Spring配置的可选方案 当描述bean如何被装配时, ...

  3. 第26章 FMC—扩展外部SDRAM—零死角玩转STM32-F429系列

    第26章     FMC—扩展外部SDRAM 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...

  4. python 教程 第二十一章、 扩展Python

    第二十一章. 扩展Python /* D:\Python27\Lib\Extest-1.0\Extest2.c */ #include <stdio.h> #include <std ...

  5. Spring学习指南-第二章-Spring框架基础(完)

    第二章 Spring框架基础 面向接口编程的设计方法 ​ 在上一章中,我们看到了一个依赖于其他类的POJO类包含了对其依赖项的具体类的引用.例如,FixedDepositController 类包含 ...

  6. 精通Web Analytics 2.0 (4) 第二章:选择你的网络分析灵魂伴侣的最佳策略

    精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第二章:选择你的网络分析灵魂伴侣的最佳策略 在Web Analytics 2.0的新世界秩序中,您必须跳出"单一真理来 ...

  7. 玩转Spring Cloud之API网关(zuul)

    最近因为工作原因,一直没有空写文章,所以都是边忙项目,边利用空闲时间,周末时间学习总结,最终在下班回家后加班加点写完本篇文章,若有不足之处,还请谅解,谢谢! 本文内容导航: 一.网关的作用 二.网关与 ...

  8. Spring IoC 容器的扩展

    前言 本篇文章主要介绍 Spring 中 BeanFactory 的扩展 ApplicationContext,我们平时日常开发中也基本上是使用它,不会去直接使用 BeanFactory. 那么在 S ...

  9. 《精通Spring4.x企业应用开发实战》第二章

    昨天联系了一下学长,学长说这个项目因为种种原因代码比较混乱,感觉最坏的打算是从头开始写. 大概询问了一下学长和xianhua学姐的建议,又看了看网上的资料,这个项目开发的技术栈基本就是SpringBo ...

随机推荐

  1. 微软ASP.NET网站部署指南(2):部署SQL Server Compact数据库

    1. 综述 对于数据库訪问,Contoso University程序要求以下的软件必须随程序一起部署.由于不属于.NET Framework: SQL Server Compact (数据库引擎) A ...

  2. C++primer中 CacheObj实现(非常有意思)

    //CacheObj.h #ifndef __CacheObj__ #define __CacheObj__ #include <iostream> #include <stdexc ...

  3. 把Excel中的数据转换成Sql语句

    假如excel表格中有A.B.C三列数据,希望导入到数据库users表中,相应的字段各自是name,sex,age ,在你的excel表格中添加一列.利用excel的公式自己主动生成sql语句,方法例 ...

  4. Ini操作类

    using System; using System.Collections; using System.Collections.Generic; using System.Linq; using S ...

  5. Linux ulimit 命令

    ulimit命令用来限制系统用户对 shell 资源的访问,常见用法如下: [root@localhost ~]$ ulimit -a # 查看当前所有的资源限制 [root@localhost ~] ...

  6. VS2015编译JPEG9b源码

    输入:nmake -f makefile.vc libjpeg.lib 出现错误:找不到win32.mak文件 按照网上说的,这个win32.mak可以在C:\Program Files (x86)\ ...

  7. unable to execute dex:GC overhead limit exceeded unable to execute dex:java heap space 解决方案

    最近做厂商适配,厂商提供了一部分Framework的jar包,把jar包通过Add Jar放到Build Path中, 在生成APK过程中,Eclipse长时间停留在100%那个进度. 最后Eclip ...

  8. 嵌入式系统UBOOT

    一个完整的嵌入式linux系统包含4部分内容:Bootloader.Parameters.Kernel.Root File System.3.4.5.6部分详细介绍了这4部分的内容,这是Linux底层 ...

  9. linux文件类型详解

    *nix 有各种的文件类型 当#ls -la后,会发现在权限位前有个 - 有些是 b 有些是 d 这个位置就是文件类型的标示   普通文件regular file,  用 - (破折号)标示, 比如 ...

  10. AndroidのBuild工具之Ant动手实践

    好久没有写博客了,没半年也应该有几个月了.在工作上的项目遇到过很多问题或者说积累了不少经验,曾经都蛮想发到博客留个纪念什么的,不求可以为别人获得点经验技巧,只求在多年后遇到同样的问题可以找到个记录.但 ...