17 Spring的代理对象

前言 

接上一篇代理介绍的文章 : https://blog.csdn.net/u011039332/article/details/96700139 

这个, 其实也还是准备了一段时间了, 好像是 7月7号开始的吧, 代理的这部分的内容花费了一些时间, 并且 空闲时间也不是太多 

我们这里关注的是 使用 cglib 来创建代理对象的相关业务处理 

 

以下相关截图, 代码基于 : jdk1.7.40 + spring-x-4.3.0 

 

 

1. 代理对象的方法调用

首先调用方方法调用大致如下 

 

BookService. add 方法上面有 @BizLogger 注解, 并且配置了 <aop:aspectj-autoproxy proxy-target-class="true"/> 

<aop:aspectj-autoproxy proxy-target-class="true"/> 部分的处理, 请参见 AspectJAutoProxyBeanDefinitionParser.parse, 主要是向容器中注册了一个 AnnotationAwareAspectJAutoProxyCreator[实现了 BeanPostProcessor] 

BizLoggerAop 的处理逻辑如下 


/**
 * BizLoggerAop
 *
 * @author Jerry.X.He
 * @version 1.0
 * @date 2016/6/8 23:00
 */
@Aspect
@Component
public class BizLoggerAop {

    @Pointcut("@annotation(com.tan.biz_log.anno.BizLogger)")
    public void bizLogPoint() {

    }

    @Around("bizLogPoint()")
    public Object doProcess(ProceedingJoinPoint point) throws Throwable {
        Log.info(" before doProcess ");
        Object result = point.proceed();
        Log.info(" after doProcess ");
        return result;
    }

    @Around("bizLogPoint()")
    public Object doProcess02(ProceedingJoinPoint point) throws Throwable {
        Log.info(" before doProcess02 ");
        Object result = point.proceed();
        Log.info(" after doProcess02 ");
        return result;
    }

    @AfterThrowing(pointcut = "bizLogPoint()", throwing = "e")
    public void doAfterThrowing(JoinPoint point, Throwable e) {
        Log.err(" exception occured with e : " + e.getMessage());
    }

}

 

由前一篇文章的 Enhancer 的介绍, 我们可以知道 "add:-1, BookService$ $EnhancerBySpringCGLIB$ $4c21d98c (com.tan.service)" 这一行的调用, 应该是 代理类里面的 "methodInterceptor.interceipt(this, method, args, methodProxy)" 的方法调用 

然后 对应我们这里的 MethodInterceptor 是 CglibAopProxy$DynamicAdvisedInterceptor 

 

CglibAopProxy$DynamicAdvisedInterceptor. intercept : 核心业务方法代理处理

这里面的大致的思路就是, 获取需要拦截的 interceptor/advise, 然后通过责任链的方式来先走完左右的 interceptor/advise, 然后 最后走 当前方法的 真实核心业务, 然后达到的效果 就是在业务方法 之前, 之后, 异常, 返回后 可以编写我们自己的一些 核心业务不敏感的, 需要模式匹配处理的业务 

 

DefaultAdvisorChainFactory. getInterceptorsAndDynamicInterceptionAdvice : 获取责任链的 interceptor 列表

获取当前方法对应的 interceptor/advise 列表, 首先获取 advised 里面的所有的 advisor, 然后 通过 advisor 获取满足条件的所有的 interceptor, 如果某些需要运行时根据实际上下文判断的 interceptor, 封装 InterceptorAndDynamicMethodMatcher 

 

ReflectiveMethodInvocation.proceed : 责任链的核心处理 

然后 创建 责任链[CglibMethodInvocation], 开始处理 各个 advise 的业务, 以及 当前 真实核心业务 

如果 interceptor/advise 是 InterceptorAndDynamicMethodMatcher 的实例, 使用给定的 matcher 传入上下文校验, 当前情况是否应该执行 interceptor/advise 的逻辑

 

CglibAopProxy$CglibMethodInvocation.invokeJoinpoint : 基于被代理对象, 以及参数 触发 核心业务 方法

调用 真实核心业务, 在 ReflectiveMethodInvocation. invokeJoinpoint 里面 使用 methodProxy 来处理给定的 方法调用, 传入触发对象, 以及参数 

CglibMethodInvocation 的对于 public 方法的处理, 是使用 methodProxy 来调用给定的方法, 里面使用 FastClass 来触发方法调用, 相比于反射, 效率要高一些吧, 相当于是直接 在代码里面写 obj.method(args), 具体的 FastClass 相关, 可以参考 FastClass, FastClassEmitter, 又或者直接 读取运行时生成的 FastClass 类

 

BookService$ $FastClassBySpringCGLIB$ $8ace9e79. invoke : FastClass 触发业务方法的调用 

  public java.lang.Object invoke(int, java.lang.Object, java.lang.Object[]) throws java.lang.reflect.InvocationTargetException;
    Code:
       0: aload_2
       1: checkcast     #86                 // class com/tan/service/BookService
       4: iload_1
       5: tableswitch   { // 0 to 6
                     0: 48
                     1: 59
                     2: 70
                     3: 74
                     4: 85
                     5: 100
                     6: 104
               default: 116
          }
      48: aload_3
      49: iconst_0
      50: aaload
      51: checkcast     #88                 // class com/tan/model/Book
      54: invokevirtual #91                 // Method com/tan/service/BookService.add:(Lcom/tan/model/Book;)V
      57: aconst_null
      58: areturn
      59: aload_3
      60: iconst_0
      61: aaload
      62: checkcast     #88                 // class com/tan/model/Book
      65: invokevirtual #93                 // Method com/tan/service/BookService.update:(Lcom/tan/model/Book;)V
      68: aconst_null
      69: areturn
      70: invokevirtual #96                 // Method com/tan/service/BookService.getBookDao:()Lcom/tan/dao/BookDao;
      73: areturn
      74: aload_3
      75: iconst_0
      76: aaload
      77: checkcast     #98                 // class com/tan/dao/BookDao
      80: invokevirtual #101                // Method com/tan/service/BookService.setBookDao:(Lcom/tan/dao/BookDao;)V
      83: aconst_null
      84: areturn
      85: aload_3
      86: iconst_0
      87: aaload
      88: invokevirtual #102                // Method com/tan/service/BookService.equals:(Ljava/lang/Object;)Z
      91: new           #104                // class java/lang/Boolean
      94: dup_x1
      95: swap
      96: invokespecial #107                // Method java/lang/Boolean."<init>":(Z)V
      99: areturn
     100: invokevirtual #108                // Method com/tan/service/BookService.toString:()Ljava/lang/String;
     103: areturn
     104: invokevirtual #109                // Method com/tan/service/BookService.hashCode:()I
     107: new           #111                // class java/lang/Integer
     110: dup_x1
     111: swap
     112: invokespecial #114                // Method java/lang/Integer."<init>":(I)V
     115: areturn
     116: goto          128
     119: new           #84                 // class java/lang/reflect/InvocationTargetException
     122: dup_x1
     123: swap
     124: invokespecial #115                // Method java/lang/reflect/InvocationTargetException."<init>":(Ljava/lang/Throwable;)V
     127: athrow
     128: new           #117                // class java/lang/IllegalArgumentException
     131: dup
     132: ldc           #119                // String Cannot find matching method/constructor
     134: invokespecial #122                // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
     137: athrow
     138: athrow
     139: new           #17                 // class java/lang/reflect/UndeclaredThrowableException
     142: dup_x1
     143: swap
     144: invokespecial #20                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
     147: athrow
    Exception table:
       from    to  target type
           5   119   119   Class java/lang/Throwable
           0   138   138   Class java/lang/RuntimeException
           0   138   138   Class java/lang/Error
           0   138   138   Class java/lang/reflect/InvocationTargetException
           0   138   139   Class java/lang/Throwable

 

 

2. 当前对象的 Advisor 列表

前面提到了一个 AnnotationAwareAspectJAutoProxyCreator, 他是一个 BeanPostProcessor, 他的角色就是 处理当前 bean, 是否需要 封装代理, 如果需要创建代理对象, 则收集 advisor 列表信息, 以及对象相关的其他上下文信息, 创建代理, 将代理对象 存入容器 

 

上面的 interceptor列表 来自于  DynamicAdvisedInterceptor.advised, 间接来自于 AbstractAutoProxyCreator. createProxy 里面创建的 ProxyFactory, 里面封装了 目标对象, 需要处理业务的 advisor 等等 

 

查询当前对象满足的 advisor 列表这边, 是 AbstractAdvisorAutoProxyCreator. findEligibleAdvisors 来处理的业务 

首先查询所有的 Advisor 对象, 然后 再筛选出符合当前 对象的 Advisor 列表, 然后创建代理  

 

2.1. 查询所有的当前对象可用的 Advisor 对象

2. 1. 1. 查询容器里面所有的 Advisor 对象 

2. 1. 2. 查询容器里面所有标记 @Aspect 的对象, 查询该类下面的所有的 @Before, @Around, @After, @AfterReturning, @AfterThrowing 的方法, 创建 AspectJExpresssionPointCut, 然后 再创建 Advisor [InstantiationModelAwarePointcutAdvisorImpl], 还可以根据 field 创建 Advisor ?

 

BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans : 查询容器里面所有的 Advisor 对象 

关于 容器里面的 Advisor 对象来源, 通常来说 来自于 解析 "<aop:config>" aop namespace 标签中的内容, 来创建 对应的 Advisor, Advise, Pointcut 等等对象, 又或者 直接手动往容器里面声明 

 

ReflectiveAspectJAdvisorFactory.getAdvisors : 根据注解查询, 并创建 Advisor 

根据 field 创建Advisor, 这个从来没有用过, 网上搜索了一下  好像还不是那么容易理解, 算了 反正也不怎么常用 

如果是可用的 Advisor 含有 AspectJ 的Advisor, 新增 ExposeInvocationInterceptor 用于暂存 methodInvocation, 也就是 后来 DynamicAdvisedInterceptor 的调用过程中的责任链角色的对象, 可以通过  ExposeInvocationInterceptor. currentInvocation 来获取当前调用的 MethodInvocation 

然后进行排序, 根据 Ordered, PriorityOrdered 接口, 或者 @Order 注解 

 

 

2. 2.  筛选出符合当前对象的 Advisor 

AopUtils.canApply : 筛选出符合当前对象的 Advisor 

 

 

3. 责任链的示例

最后演示一个责任链模式的示例, 也是 很久之前的代码了, 所以注释, 代码风格方面, 有待提升 

Main : 测试用例 

public class Main {

	public static void main(String []args){
		FilterChain fc = new FilterChain();
		fc.addFilter(new IPFilter());
		fc.addFilter(new LogFilter());
		fc.setServlet(new Servlet());
		
		fc.doFilter(new Request(), new Response());
	}
	
}
FilterChain : 责任链对象, 驱动责任链流转的上下文
public class FilterChain {

	private Filter[] filters;
	private int index;
	private Servlet servlet;
	
	public FilterChain(){
		filters = new Filter[0];
	}

	public void setServlet(Servlet servlet){
		this.servlet = servlet;
	}

	public void addFilter(Filter filter){
		Filter[] newFilter = new Filter[filters.length+1];
		System.arraycopy(filters, 0, newFilter, 0, filters.length);
		newFilter[filters.length] = filter;
		filters = newFilter;
	}
	
	public void removeFilter(Filter tarFilter){
		for(int i=0; i<filters.length; i++){
			Filter filter = filters[i];
			if(filter == tarFilter){
				removeFilter(index);
				i--;
			}
		}
	}
	
	public void removeFilter(int index){
		System.arraycopy(filters, index+1, filters, index, filters.length-index-1);
	}
	
	public void doFilter(Request request, Response response){
		if(index<filters.length){
			filters[index++].doFilter(request, response, this);
		}else{
			servlet.service(request, response);
		}
	}
	
}

 

Filter : 处理额外的业务, 或者校验 

public interface Filter {
	
	public void init();
	public void doFilter(Request request, Response response, FilterChain filterChain);
	public void destory();
	
}


public class IPFilter implements Filter {

	public void doFilter(Request request, Response response,
			FilterChain filterChain) {
		Tools.print("ip filter do sth before doFilter ... ");
		filterChain.doFilter(request, response);
		Tools.print("ip filter do sth after doFilter ... ");
	}

	public void init() {
		
	}

	public void destory() {
		
	}

}


public class LogFilter implements Filter {

	public void doFilter(Request request, Response response,
			FilterChain filterChain) {
		Tools.print("log filter do sth before doFilter ... ");
		filterChain.doFilter(request, response);
		Tools.print("log filter do sth after doFilter ... ");
	}

	public void init() {
		
	}

	public void destory() {
		
	}

}

 

Servlet : 处理业务

public class Servlet {

	public void service(Request request, Response response){
		Tools.print("Servlet do service....");
	}
	
}

 

Request, Response : 辅助上下文的对象

public class Request {

}


public class Response {

}

 

Tomcat 中的 Filter 就是责任链的一个典型的实现 

另外还有我的 简易http服务器 HXServer 里面的 Filter 也是责任链实现 

HXServer 参考 : https://blog.csdn.net/u011039332/article/details/50075125

 

 

 

完 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值