In addition to declaring aspects in your configuration by using either <aop:config> or <aop:aspectj-autoproxy>, it is also possible to programmatically create proxies that advise target objects. Here, we want to focus on the ability to automatically create proxies by using @AspectJ aspects.
You can use the org.springframework.aop.aspectj.annotation.AspectJProxyFactory class to create a proxy for a target object that is advised by one or more @AspectJ aspects. The basic usage for this class is very simple, as the following example shows:
// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
// add an aspect, the class must be an @AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager.class);
// you can also add existing aspect instances, the type of the object supplied must be an @AspectJ aspect
factory.addAspect(usageTracker);
// now get the proxy object...
MyInterfaceType proxy = factory.getProxy();
创建maven项目并引入如下的依赖包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
首先创建实体类、注解和业务类
package com.example.managingtransactions.proxy.programmatic.entity;
public class User {
private Long userId;
private String userName;
public User(Long userId, String userName) {
this.userId = userId;
this.userName = userName;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
package com.example.managingtransactions.proxy.programmatic.entity;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Usage {
}
package com.example.managingtransactions.proxy.programmatic.service;
import com.example.managingtransactions.proxy.programmatic.entity.Usage;
import com.example.managingtransactions.proxy.programmatic.entity.User;
public interface UserService {
User findUser(Long userId);
}
package com.example.managingtransactions.proxy.programmatic.service;
import com.example.managingtransactions.proxy.programmatic.entity.Usage;
import com.example.managingtransactions.proxy.programmatic.entity.User;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Usage
@Override
public User findUser(Long userId) {
return new User(userId, "TomCat");
}
}
创建两个Aspect类
package com.example.managingtransactions.proxy.programmatic.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class SecurityManager {
/**
* A join point is in the service layer if the method is defined
* in a type in the com.xyz.someapp.service package or any sub-package
* under that.
*/
@Pointcut("within(com.example.managingtransactions.proxy.programmatic.service..*)")
public void inServiceLayer() {}
@Before("inServiceLayer()")
public void before(){
System.out.println("============SecurityManager========before========");
}
}
package com.example.managingtransactions.proxy.programmatic.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class UsageTracker {
@Around("@annotation(com.example.managingtransactions.proxy.programmatic.entity.Usage)")
public Object tracker(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
try {
return joinPoint.proceed();
} finally {
long end = System.currentTimeMillis();
System.out.println("耗时" + (end - start) + "ms");
}
}
}
创建Spring配置类和启动类
package com.example.managingtransactions.proxy.programmatic;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class BootConfig {
}
package com.example.managingtransactions.proxy.programmatic;
import com.example.managingtransactions.proxy.programmatic.aspect.SecurityManager;
import com.example.managingtransactions.proxy.programmatic.aspect.UsageTracker;
import com.example.managingtransactions.proxy.programmatic.entity.User;
import com.example.managingtransactions.proxy.programmatic.service.UserService;
import com.example.managingtransactions.proxy.programmatic.service.UserServiceImpl;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class SpringStartMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BootConfig.class);
UsageTracker usageTracker = applicationContext.getBean(UsageTracker.class);
// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(new UserServiceImpl());
// add an aspect, the class must be an @AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager.class);
// you can also add existing aspect instances, the type of the object supplied must be an @AspectJ aspect
factory.addAspect(usageTracker);
// now get the proxy object...
UserService proxy = factory.getProxy();
User user = proxy.findUser(2563L);
System.out.println(user.getUserName());
applicationContext.close();
}
}
测试结果如下:
查看代理对象信息如下:
执行如下代理的方法时
// now get the proxy object...
UserService proxy = factory.getProxy();
User user = proxy.findUser(2563L);
首先进入JdkDynamicAopProxy类的invoke方法
主要的逻辑1:获取增强拦截链
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
/**
* Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects
* for the given method, based on this configuration.
* @param method the proxied method
* @param targetClass the target class
* @return a List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
*/
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
根据方法进行缓存 使用拦截器链构造工厂来真实生成拦截器链
看一下这个advisorChainFactory是怎么来的
通过AdvisorChainFactory获取拦截器增强链
@Override
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 com.example.managingtransactions.proxy.programmatic.service.UserServiceImpl
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally. 通常逻辑 转变成PointcutAdvisor
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// PreFiltered默认为false
// 1. 获取PointcutAdvisor中的ClassFilter进行过滤
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
// 2. 获取PointcutAdvisor中的MethodMatcher进行匹配
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) {
// 3. 如果方法也匹配的话 就获取方法拦截器
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;
}
AspectJ expression匹配逻辑
AspectJExpressionPointcut专门用于处理AspectJ expression,是否与当前方法匹配
// 当前类:org.springframework.aop.aspectj.AspectJExpressionPointcut
// method = public abstract com.example.managingtransactions.proxy.programmatic.entity.User com.example.managingtransactions.proxy.programmatic.service.UserService.findUser(java.lang.Long)
// targetClass = class com.example.managingtransactions.proxy.programmatic.service.UserServiceImpl
// hasIntroductions = false
@Override
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
// 获取切面语句
obtainPointcutExpression();
ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
// Special handling for this, target, @this, @target, @annotation
// in Spring - we can optimize since we know we have exactly this class,
// and there will never be matching subclass at runtime.
if (shadowMatch.alwaysMatches()) {
return true;
}
else if (shadowMatch.neverMatches()) {
return false;
}
else {
// the maybe case
if (hasIntroductions) {
return true;
}
// A match test returned maybe - if there are any subtype sensitive variables
// involved in the test (this, target, at_this, at_target, at_annotation) then
// we say this is not a match as in Spring there will never be a different
// runtime subtype.
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
}
}
深度匹配
private ShadowMatch getTargetShadowMatch(Method method, Class<?> targetClass) {
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
if (targetMethod.getDeclaringClass().isInterface()) {
// Try to build the most specific interface possible for inherited methods to be
// considered for sub-interface matches as well, in particular for proxy classes.
// Note: AspectJ is only going to take Method.getDeclaringClass() into account.
Set<Class<?>> ifcs = ClassUtils.getAllInterfacesForClassAsSet(targetClass);
if (ifcs.size() > 1) {
try {
Class<?> compositeInterface = ClassUtils.createCompositeInterface(
ClassUtils.toClassArray(ifcs), targetClass.getClassLoader());
targetMethod = ClassUtils.getMostSpecificMethod(targetMethod, compositeInterface);
}
catch (IllegalArgumentException ex) {
// Implemented interfaces probably expose conflicting method signatures...
// Proceed with original target method.
}
}
}
// 由于当前非接口 所以走这里
return getShadowMatch(targetMethod, method);
}
AdvisorAdapterRegistry解析Advisor获取方法拦截器
从以上关系图中不难看出,AdvisorAdapter用于从Advisor中获取MethodInterceptor。在DefaultAdvisorAdapterRegistry注册了常用的AdvisorAdapter,通过遍历AdvisorAdapter,解析出Advisor中的方法拦截器。
比如针对于前置处理器的AdvisorAdapter
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
整体处理逻辑
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
环绕通知也是作为MethodInterceptor来处理的
如果当前的切面语句需要运行时判断匹配的,比如注解,则需要再次进行包装
根据获取到的所有拦截器并缓存
根据代理对象、目标对象以及拦截器构造MethodInvocation对象
// 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();
ReflectiveMethodInvocation是针对代理对象、目标对象以及拦截器链的包装,当真正发起调用的时候,会遍历里面的拦截器链发起调用。
比较重要的两个参数
/**
* List of MethodInterceptor and InterceptorAndDynamicMethodMatcher
* that need dynamic checks.
*/
protected final List<?> interceptorsAndDynamicMethodMatchers;
/**
* Index from 0 of the current interceptor we're invoking.
* -1 until we invoke: then the current interceptor.
*/
private int currentInterceptorIndex = -1;
核心逻辑
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 每次根据当前的偏移量获取拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
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 {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
ExposeInvocationInterceptor拦截器逻辑:
// 通过线程局部变量进行当前调用的暴露
private static final ThreadLocal<MethodInvocation> invocation =
new NamedThreadLocal<>("Current AOP method invocation");
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
MethodBeforeAdviceInterceptor拦截器逻辑
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
// 首选执行before逻辑
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
// 执行目标方法
return mi.proceed();
}
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
运行时动态匹配->around+annotation
AspectJAroundAdvice