spring aop
一.Advisor 和 Advice
Advice,我们通常都会把他翻译为通知,其实很不好理解,其实他还有另外一个意思,就是“建议”,我觉得把Advice理解为“建议”会更好。
比如,我们已经完成了一个功能,这时客户跟我们说,我建议在这个功能之前可以再增加一些逻辑,再之后再增加一些逻辑。
在Spring中,Advice分为:
- 前置Advice:MethodBeforeAdvice
- 后置Advice:AfterReturningAdvice
- 环绕Advice:MethodInterceptor
- 异常Advice:ThrowsAdvice
Pointcut
切点,表示我想让哪些地方加上我的代理逻辑。
比如某个方法,
比如某些方法,
比如某些方法名前缀为“find”的方法,
比如某个类下的所有方法,等等。
例子:
public class LoggerAfterReturningAdvice implements AfterReturningAdvice {
// 方法执行后进行调用,后置增强 --->建议
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("AfterReturningAdvice");
}
}
public class LoggerMethodBeforeAdvice implements MethodBeforeAdvice {
// 方法执行前进行调用,前置增强
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName());
System.out.println("MethodBeforeAdvice");
}
}
public class LoggerMethodInterceptor implements MethodInterceptor {
// 可以理解为环绕通知,可以更加自由的控制是在方法执行前,后进行调用
@Override
public Object invoke(MethodInvocation i) throws Throwable {
System.out.println("method "+i.getMethod()+" is called on "+
i.getThis()+" with args "+i.getArguments());
Object ret=i.proceed();
System.out.println("method "+i.getMethod()+" returns "+ret);
return ret;
}
}
public class HxyPointcut implements Pointcut {
@Override
public ClassFilter getClassFilter() {
return ClassFilter.TRUE;
}
@Override
public MethodMatcher getMethodMatcher() {
return new StaticMethodMatcherPointcut() {
@Override
public boolean matches(@NonNull Method method, Class<?> targetClass) {
// 对于toString方法不进行拦截
return !method.getName().equals("toString");
}
};
}
}
public class LubanService {
public User test() {
System.out.println("===");
return new User("xxx");
}
@Override
public String toString() {
System.out.println("LubanService toString invoke");
return "LubanService";
}
}
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();
// 一个Advisor代表的是一个已经跟指定切点绑定了的通知
// 在这个例子中意味着环绕通知不会作用到toString方法上
Advisor advisor = new DefaultPointcutAdvisor(new HxyPointcut(), new LoggerMethodInterceptor());
proxyFactory.addAdvisor(advisor);
proxyFactory.addAdvice(new LoggerMethodBeforeAdvice());
proxyFactory.addAdvice(new LoggerAfterReturningAdvice());
proxyFactory.setTarget(new LubanService());
proxyFactory.setProxyTargetClass(true);
Object proxy = proxyFactory.getProxy();
// 调用代理类的toString方法,通过控制台查看代理逻辑的执行情况
proxy.toString();
if (proxy instanceof LubanService) {
((LubanService) proxy).test();
}
// 判断引入是否成功,并执行引入的逻辑
if (proxy instanceof Runnable) {
((Runnable) proxy).run();
}
}
环绕通知
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
invocation.proceed 就是在执行当前的这个方法
前置通知(Before Advice)
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}
后置通知(After Returning Advice)
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
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);
}
}
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
private final MethodBeforeAdvice advice;
/**
* Create a new MethodBeforeAdviceInterceptor for the given advice.
* @param advice the MethodBeforeAdvice to wrap
*/
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//实际上还是利用拦截器,在方法执行前调用了通知的before方法完成了前置通知
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed(); // methodinter target.test();
}
Advisor (绑定通知跟切点)
一个Advisor
实际上就是一个绑定在指定切点上的通知。
Advisor advisor = new DefaultPointcutAdvisor(new HxyPointcut(), new LoggerMethodInterceptor());
proxyFactory.addAdvisor(advisor);
proxyFactory.addAdvice(new LoggerMethodInterceptor());
有2种实现方式 一种直接添加一个Advisor
,还有一种是添加一个Advice
addAdvice方法如下:
@Override
public void addAdvice(Advice advice) throws AopConfigException {
int pos = this.advisors.size();
addAdvice(pos, advice);
}
public void addAdvice(int pos, Advice advice) throws AopConfigException {
Assert.notNull(advice, "Advice must not be null");
if (advice instanceof IntroductionInfo) {
// We don't need an IntroductionAdvisor for this kind of introduction:
// It's fully self-describing.
addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
}
else if (advice instanceof DynamicIntroductionAdvice) {
// 不能直接添加一个不是IntroductionInfo的DynamicIntroductionAdvice(动态引入通知)
// We need an IntroductionAdvisor for this kind of introduction.
throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
}
else {
// 如果是普通的通知,那么会创建一个DefaultPointcutAdvisor
// DefaultPointcutAdvisor所定义的切点会匹配所有类以及所有方法
addAdvisor(pos, new DefaultPointcutAdvisor(advice)); // Advisor advice pointcut
}
}
其实也是调用了addAdvisor方法
ProxyCreatorSupport
这个类的主要作用是为创建一个AOP代理对象提供一些功能支持,通过它的getAopProxyFactory
能获取一个创建代理对象的工厂。
ProxyConfig
/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = -8409359707199703185L;
// 是否开启cglib
private boolean proxyTargetClass = false;
// 跟cglib优化有关系
private boolean optimize = false;
boolean opaque = false;
// 是否将生成的代理对象设置到AopContext中去,后面可以通过AopContext.currentProxy()拿到
boolean exposeProxy = false;
private boolean frozen = false;
AdvisedSupport
1.目标对象 2.执行通知 3.实现哪些接口
AdvisedSupport
本身实现了Advised
接口,Advised
接口定义了管理通知的方法
spring 提供3种方式进行代理
ProxyFactoryBean
ProxyFactory
Auto-proxy
1.ProxyFactoryBean
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); proxyFactoryBean.setBeanFactory(applicationContext.getBeanFactory()); proxyFactoryBean.setInterfaces(Runnable.class); proxyFactoryBean.setProxyTargetClass(true); proxyFactoryBean.setTarget(applicationContext.getBean(HxyService.class)); proxyFactoryBean.setInterceptorNames("loggerMethodBeforeAdvice"); applicationContext.getBeanFactory().registerSingleton("myproxy",proxyFactoryBean); HxyService proxyBean = (HxyService) applicationContext.getBean("myproxy"); proxyBean.testAop();
3.实现自动aop代理
BeanNameAutoProxyCreator
使用方式@Bean public BeanNameAutoProxyCreator creator(){ BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator(); beanNameAutoProxyCreator.setBeanNames("luban*"); beanNameAutoProxyCreator.setInterceptorNames("loggerMethodInterceptor"); beanNameAutoProxyCreator.setProxyTargetClass(true); return beanNameAutoProxyCreator; }
2.DefaultAdvisorAutoProxyCreator 使用方式
@Bean
public DefaultPointcutAdvisor loggerBeforeAdvisor(){
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
defaultPointcutAdvisor.setAdvice(new LoggerMethodBeforeAdvice());
return defaultPointcutAdvisor;
}
@Bean
public DefaultPointcutAdvisor loggerAroundAdvisor(){
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
defaultPointcutAdvisor.setAdvice(new LoggerMethodInterceptor());
return defaultPointcutAdvisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setUsePrefix(true);
defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("logger");
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
3.AnnotationAwareAspectJAutoProxyCreator
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WZC2LTcB-1614038688601)(C:\Users\23634\AppData\Roaming\Typora\typora-user-images\image-20210222152327570.png)]
自动代理机制实际上就是Spring在内部new了一个ProxyFactory
,通过它创建了一个代理对象。对应的代码就在AbstractAutoProxyCreator
中的createProxy
方法内,源码如下:
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this); // 复制配置参数
// 是否指定了必须用cglib进行代理
if (!proxyFactory.isProxyTargetClass()) {
// 如果没有指定,那么则判断是不是应该进行cglib代理(判断BeanDefinition中是否指定了要用cglib)
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 是否进行jdk动态代理,如果当前beanClass实现了某个接口,那么则会使用JDK动态代理
evaluateProxyInterfaces(beanClass, proxyFactory); // 判断beanClass有没有实现接口
}
}
// 将commonInterceptors和specificInterceptors整合再一起
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors); // 向ProxyFactory中添加advisor
proxyFactory.setTargetSource(targetSource); // 被代理的对象
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy); //
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 生成代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
核心源码分析
createAopProxy方法分析
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// Spring到底何时使用cglib,何时使用jdk动态代理
// 如果设置的targetClass是一个接口,会使用jdk动态代理
// 默认情况下(optimize为false, isProxyTargetClass为false), ProxyFactory添加了接口时,也会使用jdk动态代理
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);
}
}
/**
* Determine whether the supplied {@link AdvisedSupport} has only the
* {@link org.springframework.aop.SpringProxy} interface specified
* (or no proxy interfaces specified at all).
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
getProxy方法分析
分析JdkDynamicAopProxy
@Override
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);
// 判断这些接口中有没有定义equals方法,hashcode方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 针对所指定的接口生成代理对象,包括用户所添加的接口以及SpringProxy、Advised、DecoratingProxy
// 所以生成的代理对象可以强制转换成任意一个接口类型
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
执行invoke方法
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// advised就是ProxyFactory
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget(); // targetSource分为两种:SingletonTargetSource、EmptyTargetSource
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 根据当前方法获取对应的拦截器链
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();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
- 获取整个拦截器链
- 开始在拦截器链上执行方法
1.获取整个拦截器链
// 根据当前正在执行的方法和被代理的类查找匹配的Advisor链
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;
}
拦截器链
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 开始在拦截器链上执行这个方法
retVal = invocation.proceed();
最后的关键代码就落在了ReflectiveMethodInvocation
的proceed
方法
@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);
}
}