Spring框架(基础篇)AOP篇

AOP:

面向切面编程。封装多个类的公共行为,讲与业务无关却被共同调用的逻辑封装起来,减少系统重复代码,降低模块间的耦合度。同时解决一些系统层面的问题,例如日志、事务、权限等。

切点表达式

Joinpoint,织入点,指需要执行代理操作的某个类的某个方法(仅支持方法级别的JoinPoint);Pointcut是JoinPoint的表述方式,能捕获JoinPoint。

最常用的切点表达式是AspectJ的切点表达式。需要匹配类,定义ClassFilter接口;匹配方法,定义MethodMatcher接口。PointCut需要同时匹配类和方法,包含ClassFilter和MethodMatcher,AspectJExpressionPointcut是支持AspectJ切点表达式的PointCut实现,简单实现仅支持execution函数。

public class PointcutExpressionTest {

	@Test
	public void testPointcutExpression() throws Exception {
		AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut("execution(* org.springframework.test.service.HelloService.*(..))");
		Class<HelloService> clazz = HelloService.class;
		Method method = clazz.getDeclaredMethod("sayHello");

		assertThat(pointcut.matches(clazz)).isTrue();
		assertThat(pointcut.matches(method, clazz)).isTrue();
	}
}

基于JDK的动态代理

在JDK中,有一个Proxy类(名词,代理人)。Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态的生成实现类,这个类提供的有一个静态方法:newProxyInstance()方法。这个方法的目的就是给我们的目标对象(委托对象)返回一个代理对象。

newProxyInstance()方法需要有三个参数:

  • 类加载器(ClassLoader对象)
  • 接口集合(一个Interface对象的数组,就是需要代理对象代理那些共同行为,也是委托对象继承的共同行为接口)
  • 一个InvocationHandler接口对象(当然可以是它的一个实现类对象)。这个接口中有一个invoke()方法。invoke()方法起到的作用很大,当代理对象调用共同行为方法的时候,invoke()方法就会被自动调用执行。
WorldService worldService = new WorldServiceImpl();
advisedSupport = new AdvisedSupport();
TargetSource targetSource = new TargetSource(worldService);
WorldServiceInterceptor methodInterceptor = new WorldServiceInterceptor();
MethodMatcher methodMatcher = new AspectJExpressionPointcut("execution(*             
         org.springframework.test.service.WorldService.explode(..))").getMethodMatcher();
advisedSupport.setTargetSource(targetSource);
advisedSupport.setMethodInterceptor(methodInterceptor);
advisedSupport.setMethodMatcher(methodMatcher);

WorldService proxy = (WorldService) new JdkDynamicAopProxy(advisedSupport).getProxy();
proxy.explode();

基于CGLIB的动态代理

基于CGLIB的动态代理实现逻辑也比较简单,查看CglibAopProxy。与基于JDK的动态代理在运行期间为接口生成对象的代理对象不同,基于CGLIB的动态代理能在运行期间动态构建字节码的class文件,为类生成子类,因此被代理类不需要继承自任何接口。

CGLB动态代理是一个开源的第三方工具库,其原理是继承,去生成目标类的子类对象,这样对子类的功能进行增强。但是要求:目标类不能用final修饰,目标类中的方法也不能被final修饰。

CGLB动态代理的效率要大于JDK动态代理的效率。

WorldService worldService = new WorldServiceImpl();
advisedSupport = new AdvisedSupport();
TargetSource targetSource = new TargetSource(worldService);
WorldServiceInterceptor methodInterceptor = new WorldServiceInterceptor();
MethodMatcher methodMatcher = new AspectJExpressionPointcut("execution(*             
         org.springframework.test.service.WorldService.explode(..))").getMethodMatcher();
advisedSupport.setTargetSource(targetSource);
advisedSupport.setMethodInterceptor(methodInterceptor);
advisedSupport.setMethodMatcher(methodMatcher);

WorldService proxy = (WorldService) new CglibAopProxy(advisedSupport).getProxy();
proxy.explode();

 

AOP代理工厂

AOP代理工厂ProxyFactory,由AdvisedSupport#proxyTargetClass属性决定采用JDK动态代理还是CGLIB动态代理。

WorldService worldService = new WorldServiceImpl();
advisedSupport = new AdvisedSupport();
TargetSource targetSource = new TargetSource(worldService);
WorldServiceInterceptor methodInterceptor = new WorldServiceInterceptor();
MethodMatcher methodMatcher = new AspectJExpressionPointcut("execution(*             
         org.springframework.test.service.WorldService.explode(..))").getMethodMatcher();
advisedSupport.setTargetSource(targetSource);
advisedSupport.setMethodInterceptor(methodInterceptor);
advisedSupport.setMethodMatcher(methodMatcher);


// 使用JDK动态代理
advisedSupport.setProxyTargetClass(false);
WorldService proxy = (WorldService) new ProxyFactory(advisedSupport).getProxy();
proxy.explode();

// 使用CGLIB动态代理
advisedSupport.setProxyTargetClass(true);
proxy = (WorldService) new ProxyFactory(advisedSupport).getProxy();
proxy.explode();

PointcutAdvisor:Pointcut和Advice的组合

PointcutAdvisor是包含一个Pointcut和一个Advice的组合,Pointcut用于捕获JoinPoint,Advice决定在JoinPoint执行某种操作。实现了一个支持aspectj表达式的AspectJExpressionPointcutAdvisor。

public class DynamicProxyTest {

	@Test
	public void testAdvisor() throws Exception {
		WorldService worldService = new WorldServiceImpl();

		//Advisor是Pointcut和Advice的组合
		String expression = "execution(* org.springframework.test.service.WorldService.explode(..))";
		AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
		advisor.setExpression(expression);
		MethodBeforeAdviceInterceptor methodInterceptor = new MethodBeforeAdviceInterceptor(new WorldServiceBeforeAdvice());
		advisor.setAdvice(methodInterceptor);

		ClassFilter classFilter = advisor.getPointcut().getClassFilter();
		if (classFilter.matches(worldService.getClass())) {
			AdvisedSupport advisedSupport = new AdvisedSupport();
			TargetSource targetSource = new TargetSource(worldService);
			advisedSupport.setTargetSource(targetSource);
			advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
			advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
//			advisedSupport.setProxyTargetClass(true);   //JDK or CGLIB

			WorldService proxy = (WorldService) new ProxyFactory(advisedSupport).getProxy();
			proxy.explode();
		}
	}
}

 

动态代理融入bean生命周期

结合前面讲解的bean的生命周期,BeanPostProcessor处理阶段可以修改和替换bean,正好可以在此阶段返回代理对象替换原对象。不过我们引入一种特殊的BeanPostProcessor——InstantiationAwareBeanPostProcessor,如果InstantiationAwareBeanPostProcessor处理阶段返回代理对象,会导致短路,不会继续走原来的创建bean的流程。

具体流程如下:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值