拦截篇-AOP怎么拦截类和方法
Joinpoint
Joinpoint(连接点)是面向切面编程(Aspect-Oriented Programming, AOP)中的一个核心概念。在 Spring AOP 中,它主要指代的是应用程序中的某个特定点,在这个点上可以应用切面(Aspect)的逻辑。具体来说,Joinpoint 通常指的是方法执行的开始或结束点,也可以是在执行构造器、处理异常抛出或其他特定程序结构上的点。
在 Spring AOP 的上下文中,Joinpoint 主要指的是方法执行点。这意味着你可以将切面逻辑添加到方法调用之前、之后或周围。例如,你可以在方法调用前添加日志记录,在方法调用后清理资源,或者在方法调用前后进行事务管理。
我们看到JointPoint下面是Invocation,由于Spirng只支持方法的拦截,所以右边的构造器拦截没有对应的实现。
MethodInvocation 有两种实现,一种是反射基于jdk动态代理,一种是cglib动态代理。
public interface Joinpoint {
// 执行下一个拦截器并返回值,对应的就是方法的执行
Object proceed() throws Throwable;
// 返回持有当前连接点的对象
Object getThis();
// 这里其实就是被拦截的方法
AccessibleObject getStaticPart();
}
public interface Invocation extends Joinpoint {
/**
* 获取拦截方法的参数,可以通过改变数组的值来改变参数
*/
Object[] getArguments();
}
// 下面这个接口也写了getMethod 返回的是和getStaticPart返回一样的结果,也就证明了getStaticPart返回的是被拦截的这个方法
public interface MethodInvocation extends Invocation {
/**
* Get the method being called.
* <p>This method is a friendly implementation of the
* {@link Joinpoint#getStaticPart()} method (same result).
* @return the method being called
*/
Method getMethod();
}
Pointcut
有了连接点,我们只在符合条件的连接点进行切入。Pointcut就是用于匹配JointPoint 的条件,决定了我们是不是在这些切入点进行接入。
public interface Pointcut {
// 判断类是否符合
ClassFilter getClassFilter();
// 判断方法是否符合
MethodMatcher getMethodMatcher();
// 默认拦截所有的所有的类
Pointcut TRUE = TruePointcut.INSTANCE;
}
public interface MethodMatcher {
// 方法是否满足 这个是方法非动态生成不检验参数
boolean matches(Method method, Class<?> targetClass);
// 是不是运行时,指的是这个方法是不是被动态创建的
boolean isRuntime();
// 参数是否满足要求,这个可以用于我们对参数进行一系列判断操作,如果isRuntime返回false这个方法不会被调用。
boolean matches(Method method, Class<?> targetClass, Object... args);
// 默认拦截所有的方法
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
PointCut根据ClassFilter 先拦截类,然后根据MethodMatcher拦截方法。
PointCut的使用方式
使用方式一 直接实现Pointcut
public class ImplPointcut implements Pointcut {
// 由于这个是静态的其实我们只需要创建一次以后进行复用就行了所以直接使用单例模式
public static final ImplPointcut INSTANCE = new ImplPointcut();
@Override
public ClassFilter getClassFilter() {
return new ClassFilter() {
@Override
public boolean matches(Class<?> clazz) {
return clazz.isAssignableFrom(Client.class);
}
};
}
@Override
public MethodMatcher getMethodMatcher() {
return new MethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
// 只要是方法名为execute就进行拦截
return method.getName().equals("execute");
}
@Override
public boolean isRuntime() {
return false;
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
return false;
}
};
}
}
public class CustomMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
System.out.println("==========执行拦截===" + method);
// 这里一定要调用否则方法不会执行
return invocation.proceed();
}
}
public class Client {
public static void main(String[] args) {
// 定义一个切面 里面制定了我们要拦截的方法及我们要拦截的规则
ImplPointcut pointCut = ImplPointcut.INSTANCE;
// 定义一个被代理对象
Client client = new Client();
// 创代理对象
ProxyFactory proxy = new ProxyFactory(client);
// pointCut容器
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointCut, new CustomMethodInterceptor());
proxy.addAdvisor(advisor);
// 通过代理获取对象
Client proxyClient = (Client) proxy.getProxy();
proxyClient.execute();
}
public void execute() {
System.out.println("================== 执行方法内部逻辑 ==============");
}
}
使用方式二直接继承StaticMethodMatcherPointcut
因为这个在StaticMethodMatcherPointcut 已经实现了ClassFilter 默认为true,也就是拦截所有的类,我们只需要实现方法的matchs就行了。
public class ApiPointCut extends StaticMethodMatcherPointcut {
// 要拦截的方法
private final String methodName;
// 要拦截的类
private final Class targetClass;
public ApiPointCut(String methodName, Class targetClass) {
super();
this.methodName = methodName;
this.targetClass = targetClass;
}
@Override
public boolean matches(Method method, Class<?> targetClass) {
return Objects.equals(methodName, method.getName())
&& (this.targetClass.isAssignableFrom(targetClass) || this.targetClass == targetClass);
}
}
使用方式三 继承JdkRegexpMethodPointcut
基于正则的判断,可以看到我们有两个数组,相当于配置了白名单和黑名单。
使用方式四 继承ControlFlowPointcut
这个是和当前的堆栈进行匹配,有这样几个问题:
1 有可能堆栈链路很长
2 在获取堆栈信息的时候是同步的有性能损耗
在new Throable()的时候会去执行fillInStackTrace是一个同步的方法:
所以不推荐使用,因为效率会比较的低下
PointCut的组合ComposablePointcut
在jdk里面如果是这个类对应的工具类一般是以s结尾,比如ClassFilters,MethodMatchers,Pointcuts,Objects他们都是工具类,下面的求交或取并集都借助了工具类
主要是靠这几个方法进行了PointCut的组合:
可以看到如果是求交集,所有的都要匹配:
如果是求并集则是,匹配到第一个成功的就认为成功:
PointCut AspectJ实现
我们看到PointCut有很多实现,其中ExpressionPointcut下面有AspectJExpressionPointcut实现。正是由于这个实现的存在我们可以写切面表达式。
支持下面这些切入点原语,Spring桥接了AspectJ的能力来和Spirng的PointCut进行整合。也就是说Spring实际上是调用是Aspectj的实现,这块的源代码太多了,这里不贴了。直接搜这个类就可以看到有构造PointCut,初始化Pointcutparser等方法。
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* com.liyong.learn.pointcut.Client.echo())");
Client client = new Client();
ProxyFactory factory = new ProxyFactory(client);
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before method");
}
});
factory.addAdvisor(advisor);
Client proxy = (Client) factory.getProxy();
proxy.echo();
通知篇-AOP实现Advice通知
Advice通知(分为befroe, after, around需要手动调用)
Around Advice - Interceptor
- 方法拦截器 - MethodInterceptor
- 构造器拦截-ConsturctInterceptor(没有进行实现)
Around Advice 重新定义直接通过Interceptor进行操作
前置动作
标准接口:BeforeAdvice
方法级别:MethodBeforeAdvice(只支持方法级别的拦截)
- 标准实现,没有引入aspectj的实现
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
private final MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
// 这个方法来自于MethodInterceptor
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
}
// 通过这个案例我们发现拦截会先到MethodBeforeAdviceInterceptor
// 然后才是MethodBeforeAdvice的拦截调用的是匿名内部类的方法
public static void main(String[] args) {
Map<String, Object> map = new HashMap<>();
ProxyFactory factory = new ProxyFactory(map);
factory.addAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
if (method.getName().equals("put")) {
System.out.println("=========== 前置拦截 ================");
}
}
});
Map<String, Object> proxy = (Map<String, Object>) factory.getProxy();
proxy.put("1", 1);
}
MethodBeforeAdvice有多少个对应的就有多少个MethodBeforeAdviceInterceptor的实现, 其实本质上都是通过MethodInterceptor来实现的
- AspectJ实现
正是有了AspectJ实现, 才支持表达式@Before(“execution(* com.example.service..(…))”)
// 也会被转换为MethodBeforeAdviceInterceptor
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
public AspectJMethodBeforeAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
// 核心逻辑
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
@Override
public boolean isBeforeAdvice() {
return true;
}
@Override
public boolean isAfterAdvice() {
return false;
}
}
后置动作
AfterAdvice
AfterReturningAdvice
ThrowsAdvice
三者不太可能同时出现
- AfterReturningAdvice
// AfterReturningAdvice标准实现
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
- ThrowsAdvice
public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
private static final String AFTER_THROWING = "afterThrowing";
private static final Log logger = LogFactory.getLog(ThrowsAdviceInterceptor.class);
private final Object throwsAdvice;
private final Map<Class<?>, Method> exceptionHandlerMap = new HashMap<>();
public ThrowsAdviceInterceptor(Object throwsAdvice) {
Assert.notNull(throwsAdvice, "Advice must not be null");
this.throwsAdvice = throwsAdvice;
Method[] methods = throwsAdvice.getClass().getMethods();
for (Method method : methods) {
// 我们添加的这个方法需要等于 afterThrowing 并且这个只提供了两种方式 要么是传一个参数要么就是传4个参数
if (method.getName().equals(AFTER_THROWING) &&
(method.getParameterCount() == 1 || method.getParameterCount() == 4)) {
Class<?> throwableParam = method.getParameterTypes()[method.getParameterCount() - 1];
if (Throwable.class.isAssignableFrom(throwableParam)) {
// An exception handler to register...
this.exceptionHandlerMap.put(throwableParam, method);
if (logger.isDebugEnabled()) {
logger.debug("Found exception handler method on throws advice: " + method);
}
}
}
}
if (this.exceptionHandlerMap.isEmpty()) {
throw new IllegalArgumentException(
"At least one handler method must be found in class [" + throwsAdvice.getClass() + "]");
}
}
public int getHandlerMethodCount() {
return this.exceptionHandlerMap.size();
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
// 发生异常的时候回去找对应的处理方法进行处理,这个处理方法是由我们在设置Advice的时候进行设置的
Method handlerMethod = getExceptionHandler(ex);
if (handlerMethod != null) {
invokeHandlerMethod(mi, ex, handlerMethod);
}
throw ex;
}
}
}
使用:
public class ThrowsAdviceDemo {
public static void main(String[] args) {
Demo demo = new Demo();
ProxyFactory factory = new ProxyFactory(demo);
factory.addAdvice(new ThrowsAdvice() {
public void afterThrowing(Exception e) {
System.out.printf("Exception : %s \n", e);
}
public void afterThrowing(Method method, Object[] args, Object target, Exception e) {
System.out.printf("Exception : %s args : %s target %s, exception %s\n", method, Arrays.asList(args), target, e);
}
});
Demo proxy = (Demo) factory.getProxy();
proxy.echo();
}
}
这是因为匿名内部类不是public 所以我们将这个定义到外面去。
public class ThrowsDemo implements ThrowsAdvice {
public void afterThrowing(Exception e) {
System.out.printf("Exception : %s \n", e);
}
public void afterThrowing(Method method, Object[] args, Object target, Exception e) {
System.out.printf("Exception : %s args : %s target %s, exception %s\n", method, Arrays.asList(args), target, e);
}
}
factory.addAdvice(new ThrowsDemo());
- aspectJ实现
public class AspectJAfterAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
public AspectJAfterAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
// 在这里实现了我们定义的throws拦截
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
@Override
public boolean isBeforeAdvice() {
return false;
}
@Override
public boolean isAfterAdvice() {
return true;
}
}
整合篇 Pointcut 与 Advice 容器
PointcutAdvisor 的作用
- 封装通知和切入点:PointcutAdvisor 接口将通知(Advice)和切入点(Pointcut)封装在一起,使得可以在运行时确定哪些连接点(Joinpoint)应该应用通知。
- 灵活性:通过将通知和切入点分离,PointcutAdvisor 提供了更大的灵活性,使得可以在不改变通知逻辑的情况下更改切入点的定义。
- 统一管理:它提供了一个统一的接口来管理通知和切入点,便于管理和配置。
Pointcut 与 Advice连接器 PointAdvisor
- 通用实现:DefaultPointcutAdvisor
- AspectJ实现:AspectJExpressionPointcutAdvisor,AspectJPointcutAdvisor
主要是提供了设置pointcut和操纵顺序的能力
- 静态方法实现:StaticMethodMatcherPointcutAdvisor
- IOC容器实现:AbstractBeanFactoryPointcutAdvisor
public interface PointcutAdvisor extends Advisor {
// 获取pointcut的能力
Pointcut getPointcut();
}
public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor {
private Advice advice = EMPTY_ADVICE;
// 存储了Advice
public void setAdvice(Advice advice) {
this.advice = advice;
}
}
// 提供了顺序能力
public abstract class AbstractPointcutAdvisor implements PointcutAdvisor, Ordered, Serializable {
// 有Advice
private final AbstractAspectJAdvice advice;
// 有PointCut
private final Pointcut pointcut;
}
IntroductionAdvisor
public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
ClassFilter getClassFilter();
void validateInterfaces() throws IllegalArgumentException;
}
// 提供了获取接口的能力
public interface IntroductionInfo {
Class<?>[] getInterfaces();
}
IntroductionAdvisor提供了动态设置范围的能力,比如我们实现了两个接口,但是我们只想其中的一个接口被代理,或者我们希望拓展一个接口(当然这个接口最好是被我们的目标对象所实现)
public class Client implements EchoService, RandomService{
public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory();
factory.setTarget(new Client());
factory.addAdvisors(new DefaultIntroductionAdvisor(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before");
}
}, new IntroductionInfo() {
@Override
public Class<?>[] getInterfaces() {
return new Class[]{EchoService.class};
}
}));
EchoService echoService = (EchoService) factory.getProxy();
RandomService randomService = (RandomService) factory.getProxy();
echoService.echo();
randomService.getRandomNum();
}
@Override
public void echo() {
System.out.println("output a word");
}
@Override
public int getRandomNum() {
return 0;
}
}
这段代码是会报错的,因为我们申明了只代理一个接口,所以无法转换为RandomService。
如果这样写就没有这个错误,两个接口都会被代理:
// 因为我们set方法没有去获取这个对象的所有接口
ProxyFactory factory = new ProxyFactory(new Client());
因为这样写构造方法里面默认获取了代理对象的所有的接口:
当然我们可以继续进行拓展,上面提到了一般我们不这么使用,最好是我们被代理的对象也要实现这个接口,如果我们明确不需要代理某一个接口可以通过上面getInterfaces 排除这个接口:
public Class<?>[] getInterfaces() {
return new Class[]{EchoService.class, RandomService.class, Comparable.class};
}
适配篇 AdvisorAdapter
AdvisorAdapter(Interceptor适配器)
接口允许扩展到Spring AOP框架,以允许处理新的advisor和Advice类型。实现对象可以从自定义通知类型创建AOP拦截器,使这些通知类型可以在Spring AOP框架中使用,它在底层使用拦截。
// 可以验证,所有的Advice都是通过Interceptor来实现的,后面都返回了一个Interceptor
// 先判断是否支持,如果支持就进行下一步操作
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
我的理解是引入适配器提供了拓展性,可以让我们除了AOP提供的这几种通知以外的通知,我们只需要定制一个拦截器即可。
代理对象生成篇
AopProxy(提供了获取代理对象的能力)
public interface AopProxy {
Object getProxy();
Object getProxy(@Nullable ClassLoader classLoader);
}
AopProxy 通过AdvisedSupport关联
AdvisedSupport 类则包含了创建代理所需的所有配置信息,比如目标对象、通知(advice)、切点(pointcut)等
AopProxy 通过内部持有 AdvisedSupport 的实例来获取创建代理所需的配置信息。当需要创建一个新的代理对象时,AopProxy 会根据 AdvisedSupport 中的信息来决定使用哪种代理机制,并完成代理对象的创建。
// 从而可以进行配置实现工厂
private final AdvisedSupport advised;
我们可以看到默认就是DefaultAopProxyFactory来进行实现创建AopProxy。
//所以默认情况下只有两种情况Jdk动态代理或者是Cglib字节码提升
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
如果我们希望替换Factory进行拓展,可以通过下面方式:
字节码生成的两种方式
JdkDynamicAopProxy
// 一个config对应了一个Factory 是通过config进行约束的 并且是通过DefaultAopProxyFactory进行创建
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
// 如果没有关联动作 Advice
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
// 获取代理对象
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 获取advice 拦截链(MethodIntercepter链表)
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
CglibAopProxy
// 这里定义了一些常量
private static final int AOP_PROXY = 0;
private static final int INVOKE_TARGET = 1;
private static final int NO_OVERRIDE = 2;
private static final int DISPATCH_TARGET = 3;
private static final int DISPATCH_ADVISED = 4;
private static final int INVOKE_EQUALS = 5;
private static final int INVOKE_HASHCODE = 6;
// 多了一个分发对象
public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
// 加了一个分发器
this.advisedDispatcher = new AdvisedDispatcher(this.advised);
}
我们可以看到CallBack其实也是MethodInterceptor:
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 这一步的执行实际上是上面获取的责任链 一个Advice列表
// 这里有个游标 如果没有Advice 或者是最后一个Advice都会执行invokeJoinpoint()
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
AopProxyFactory配置管理器AdvisedSupport
这个类下面的子类通常是工厂类,这个类存储了Advices 和 Advisors ,TragetSource等 但是没有实现创建代理对象的方法,创建对象的方法是被子类实现。
//继承了ProxyConfig 实现了Advised 接口 提供了配置 和 增加Advice等能力
public class AdvisedSupport extends ProxyConfig implements Advised {}
AdvisorChainFactory
它只有一种实现DefaultAdvisorChainFactory
// 核心方法
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
if (match) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
被代理对象的来源
targetSource
被代理的目标对象,可以有以下来源。
SingletonTargetSource(单例模式)
AbstractBeanFactoryBasedTargetSource(可以与IOC打通)
AbstractPrototypeBasedTargetSource
- AbstractPoolingTargetSource
- CommonsPool2TargetSource
- CommonsPoolTargetSource
- PrototypeTargetSource(原型模式)
- ThreadLocalTargetSource
HotSwappableTargetSource (可以动态的替换)
代理对象的创建
ProxyCreatorSupport
使得我们可以配置创建AopProxyFactory
- 标准实现ProxyFactory并没有拓展很多内容,基本的功能还是来源于父类ProxyCreatorSupport。
- ProxyFactoryBean 与IOC进行打通
public class ProxyFactoryBean extends ProxyCreatorSupport
implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {}
- AspectJ实现
AspectJAdvisorFactory 通过反射射获取Advice ReflectiveAspectJAdvisorFactory - IOC容器自动代理实现(AbstractAutoProxyCreator)
- 默认实现DefaultAdvisorAutoProxyCreator
- 名称匹配实现BeanNameAutoProxyCreator
- InfrastructureAdvisorAutoProxyCreator
-
IOC 容器自动代理抽象
-
IOC AspectJ自动实现 AspectJAwareAdvisorAutoProxyCreator
-
AOP Infrastructure Bean 接口
AdvisedSupportListener
可以监听我们Advice的变化,其原理如下,添加完以后会主动调用changed,发生变化以后可以得到通知:
public class Client implements EchoService {
public static void main(String[] args) {
Client client = new Client();
ProxyFactory proxyFactory = new ProxyFactory(client);
proxyFactory.addAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("===========> before");
}
});
proxyFactory.addListener(new AdvisedSupportListener() {
@Override
public void activated(AdvisedSupport advised) {
System.out.println("===========> activate");
}
@Override
public void adviceChanged(AdvisedSupport advised) {
System.out.println("===========> change");
}
});
EchoService proxy = (EchoService) proxyFactory.getProxy();
proxy.echo();
proxyFactory.addAdvice(new AfterReturningAdvice() {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("afterReturning");
}
});
}
@Override
public void echo() {
System.out.println("echo");
}
}
Spring AOP工具类
AOP 上下文辅助类
API - org.springframework.aop.framework.AopContext
• 语义 - ThreadLocal 的扩展,临时存储 AOP 对象
AOP 工具类
API - org.springframework.aop.framework.AopProxyUtils
• 代表方法
• getSingletonTarget - 从实例中获取单例对象
• ultimateTargetClass - 从实例中获取最终目标类
• completeProxiedInterfaces - 计算 AdvisedSupport 配置中所有被代理的接口
• proxiedUserInterfaces - 从代理对象中获取代理接口
• isAopProxy- 判断对象是否为代理对象
• isJdkDynamicProxy - 判断对象是否为 JDK 动态代理对象
• isCglibProxy - 判断对象是否为 CGLIB 代理对象
• getTargetClass - 从对象中获取目标类型
• invokeJoinpointUsingReflection - 使用 Java 反射调用 Joinpoint(目标方法)
AspectJ Enable 模块驱动实现
注解 - org.springframework.context.annotation.EnableAspectJAutoProxy
• 属性方法
• proxyTargetClass - 是否已类型代理
• exposeProxy - 是否将代理对象暴露在 AopContext 中
• 设计模式 - @Enable 模块驱动
• ImportBeanDefinitionRegistrar 实现 -
org.springframework.context.annotation.AspectJAutoProxyRegistrar
• 底层实现
• org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
参考资料:小马哥极客时间AOP。