欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

《spring技术内幕》读书笔记3-AOP的实现

程序员文章站 2022-03-09 08:04:42
目录1. Demo2. AOP过程解析2.1 生成代理2.2 执行代理逻辑1. Demo首先是大家很熟悉的spring aop应用:(1)准备工作://工人接口public interface Worker {void work();}//普通工人类public class OrdinaryWorker implements Worker {@Overridepublic void work() {System.out.println("*....

目录

1. Demo

2. AOP的实现

2.1 生成代理

2.1.1 ProxyFactoryBean的UML

2.1.2 ProxyFactoryBean的getObject()

2.2 执行拦截

2.2.1 JdkDynamicAopProxy


1. Demo

首先是spring aop应用:

(1)准备工作:

初期只需要了解:advice接口的实现类描述了:aop代理要做什么事;pointcut接口的实现类描述了:aop代理在哪里做事;advisor则是对advice、pointcut的整合。

package com.abc;

//工人接口
public interface Worker {
	void work();
}

//普通工人类
public class OrdinaryWorker implements Worker {
	@Override
	public void work() {
		System.out.println("* * * * * 搬砖 * * * * *");
	}
}

//资本家类
public class Capitalist {
	public void work() {
		System.out.println("$ ¥ $ ¥ $ ¥ $ ¥ $ ¥ $ ¥ $");
	}
}

//工人增强器(手动滑稽)
public class WorkerAdvisor extends AbstractPointcutAdvisor {

	@Override
	public Advice getAdvice() {
		return new WorkerAdvice();
	}

	@Override
	public Pointcut getPointcut() {
		String pattern = "com.abc.OrdinaryWorker.*";
		JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
		pointcut.setPattern(pattern);
		return pointcut;
	}

	static class WorkerAdvice implements AfterReturningAdvice, MethodBeforeAdvice {
		@Override
		public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
			System.out.println("21:00 - 滴,下班:没有困难的工作,只有勇敢的打工人!");
		}
		@Override
		public void before(Method method, Object[] args, Object target) throws Throwable {
			System.out.println("9:00 - 滴,上班:早安打工人!");
		}
	}
}

//资本家增加器
public class CapitalistAdvisor extends AbstractPointcutAdvisor {

	@Override
	public Advice getAdvice() {
		return new CapitalistAdvice();
	}

	@Override
	public Pointcut getPointcut() {
		String pattern = "com.abc.Capitalist.*";
		JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
		pointcut.setPattern(pattern);
		return pointcut;
	}

	static class CapitalistAdvice implements AfterReturningAdvice {
		@Override
		public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
			System.out.println("(*^▽^*)又是愉快数钱的一天!");
		}
	}
}

(2)spring配置:

<bean id="workerAdvisor" class="com.abc.WorkerAdvisor"/>
<bean id="capitalistAdvisor" class="com.abc.CapitalistAdvisor"/>

<bean id="worker" class="com.abc.OrdinaryWorker"/>
<bean id="capitalist" class="com.abc.Capitalist"/>

<bean id="aopWorker" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="target">
		<ref bean="worker"/>
	</property>
	<property name="interceptorNames">
		<list>
			<value>workerAdvisor</value>
			<value>capitalistAdvisor</value>
		</list>
	</property>
</bean>

<bean id="aopCapitalist" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="target">
		<ref bean="capitalist"></ref>
	</property>
	<property name="interceptorNames">
		<list>
			<value>workerAdvisor</value>
			<value>capitalistAdvisor</value>
		</list>
	</property>
</bean>

(3)单测:

public class AopTest {
	@Test
	public void test() throws Exception {
		BeanFactory bf = new XmlBeanFactory(new ClassPathResource("mytest/aoptest.xml"));
		Object aopWorker = bf.getBean("aopWorker");
		Object aopCapitalist = bf.getBean("aopCapitalist");

		assert !(aopCapitalist instanceof Proxy);
		assert aopWorker instanceof Proxy;

		Capitalist capitalist = (Capitalist) aopCapitalist;
		capitalist.work();
		System.out.println("--------阶级分割线--------");
		Worker worker = (Worker) aopWorker;
		worker.work();
	}
}

(4)执行结果:

$ ¥ $ ¥ $ ¥ $ ¥ $ ¥ $ ¥ $
(*^▽^*)又是愉快数钱的一天!
--------阶级分割线--------
9:00 - 滴,上班:早安打工人!
* * * * * 搬砖 * * * * *
21:00 - 滴,下班:没有困难的工作,只有勇敢的打工人!

思考:为什么断言能顺利执行 —— aopCapitalist不是Proxy的实例,而aopWorker是Proxy的实例???且看下面分解……

 

2. AOP的实现

2.1 生成代理

spring是如何生成目标对象的代理,即解读:Object aopWorker = bf.getBean("aopWorker");

2.1.1 ProxyFactoryBean的UML

"aopWorker"的类型是ProxyFactoryBean,UML图如下:

《spring技术内幕》读书笔记3-AOP的实现

根据1:ProxyFactoryBean是工厂Bean,参考【读书笔记2-依赖注入】可知执行工厂bean的getObject方法

根据2:ProxyFactoryBean能感知自己所在的BeanFactory,参考《Spring技术内幕-第2版》2.5.7节

根据3:ProxyFactoryBean继承AdvisedSupport,有几个关键的成员变量:targetSource(被代理的目标对象)、interfaces(代理的接口)、advisors(增强器)

2.1.2 ProxyFactoryBean的getObject()

了解完PRoxyFactoryBean的getObject()逻辑后,单测的问题就有答案了。主要逻辑如下:

《spring技术内幕》读书笔记3-AOP的实现

考虑到继承关系,通过property标签,既可以配置诸如:interceptorNames、targetName等来自ProxyFactoryBean的成员变量,也可以配置诸如targetSource、interfaces、advisors等来自AdvisedSupport的成员变量。

无论是基于jdk动态代理的JdkDynamicAopProxy,还是基于cglib的ObjenesisCglibAopProxy,都有1个成员变量:AdvisedSupport advised,记录了代理目标的配置信息。

2.2 执行拦截

spring生成目标对象的代理后,代理对象是如何执行被aop拦截的方法,即解读:((Worker) aopWorker).work()。

从2.1节可知,AopProxy有2种实现:JdkDynamicAopProxy、ObjenesisCglibAopProxy,下面就分析一下JdkDynamicAopProxy的情况

2.2.1 JdkDynamicAopProxy

Java动态代理对象执行被代理的接口方法时,会执行InvocationHandler接口的invoke()方法。

JdkDynamicAopProxy实现了InvocationHandler接口,invoke()方法的主要逻辑如下:

《spring技术内幕》读书笔记3-AOP的实现

从整体大局了解代码逻辑后,很自然的明白为什么chain的泛型是Object,而不是Interceptor,因为元素还可能是InterceptorAndDynamicMethodMatcher类型。而isRuntime这种情况,应该是针对方法重载的情况,相同的方法签名信息,入参类型不同,需要运行时再判断是否匹配。

aop对于不同advice转成不同MethodInterceptor,采用了适配器模式。aop的几个关键元素关系大致如下:

《spring技术内幕》读书笔记3-AOP的实现

 

本文地址:https://blog.csdn.net/ye201622021113/article/details/109590403