目录
一、动态代理模式
首先我们先聊一下动态代理,先从一个案例开始讲起:小明是一个程序员,每天都要996,没时间找女朋友,然后他的父母帮他找对象,然后找到之后再结婚生子。
这个场景中:
- 小明是被代理对象
- 小明的父母:小明的代理,帮助小明找对象
- 是对小明的一个功能增强:小明没时间找对象,找到之后帮他结婚生子
动态代理中有一下几个内容:
- 被代理对象
- 代理对象
- 增强、通知
使用jdk动态代理来实现:
1、先定义一个接口
public interface People{
void findMM();
}
2、小明
public class Xiaoming implements People{
@Override
public void findMM() {
System.out.println("小明经常加班到很晚,没时间找女朋友,需要找个mm来释放他的双手");
}
}
3、小明的父母
package com.chen.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 增强
*/
public class Parent implements InvocationHandler {
private People people;
public Parent(People people) {
this.people = people;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeMethod();
method.invoke(people);
afterMethod();
return null;
}
private void afterMethod() {
System.out.println("父母帮小明带小孩");
}
private void beforeMethod() {
System.out.println("父母帮小明找对象");
}
}
4、编写测试类
package com.chen.proxy;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
Xiaoming xiaoming = new Xiaoming();
//使用Appclassloader去加载class文件
People o = (People) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class<?>[]{People.class}, new Parent(xiaoming));
o.findMM();
}
}
那现在有个问题:Parent implements InvocationHandler,invoke方法是谁调用的呢?
首先Proxy.newProxyInstance用来创建代理对象,其中有三个参数:
- 第一个参数是类加载器
- 第二个参数是代理类要实现的接口列表
- 第三个参数是代理类(实现InvocationHandler)
我们使用一副图来整理下调用的过程
然后看$Proxy0.class文件的代码如下:
public final class $Proxy0 extends Proxy implements People {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void findMM() throws {
try {
//h其实就是Parent对象,这里会调Parent的invoke方法
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.chen.myspring.proxy.People").getMethod("findMM");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
newProxyInstance这个方法会生成一个代理实例,那生成的步骤是什么?
- 1、生成一个java类,通过字符串拼凑出来$Proxy0这个类,以.java结尾
- 2、把字符串用流的方式写到$Proxy0.java文件
- 3、把java文件编译成class文件
- 4、把.class文件加载到jvm内存
- 5、在内存里面执行,然后返回代理实例
2、spring实现AOP的流程
1) 首先要加上@EnableAspectJAutoProxy注解,@EnableAspectJAutoProxy Import了一个AspectJAutoProxyRegistar,然后将AnnotationAwareAspectJAutoProxyCreator注册到IOC容器中,beanDefinition的名称是org.springframework.aop.config.internalAutoProxyCreator,其中AnnotationAwareAspectJAutoProxyCreator继承了AbstractAutoProxyCreator。
源码如下:
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
2) AnnotationAwareAspectJAutoProxyCreator实现了BeanProcessor,然后会在执行registerBeanPostProcessors的过程中实例化这个类
3) 在执行initializeBean方法的时候会调用到AnnotationAwareAspectJAutoProxyCreator,然后执行它的postProcessAfterInitialization,执行wrapIfNecessary,然后执行findEligibleAdvisors,首先会容器中查找Advisor的实现类,这是spring的一个扩展点
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
4) 然后从容器中获取所有的bean定义的名称,判断是否有@Aspect注解,如果有@Aspect注解的类,则获取并且遍历这个类中没有@Pointcut注解的方法 , 从注解中获取切点表达式,包装成Pointcut对象,创建一个Advisor切面类,Advisor=pointcut+advice,然后根据注解生成不同的对象:AspectJAroundAdvice , AspectJAfterAdvice , AspectJAfterThrowingAdvice , AspectJMethodBeforeAdvice,AspectJAfterReturningAdvice,即一个pointcut对应多个advice,然后将得到的advice和pointcut包装成Advisor之后,添加到Advisor的容器中。判断当前的bean是否可以匹配候选的Advisors,即根据ClassFilter(判断当前bean是否在表达式中)和MethodMatcher(获取bean的所有方法,看是否和Advisor中的MethodMathcer匹配)
5) 对Advisor进行执行顺序排序:
- @Around前置
- @Before
- 执行joinPoint.proceed();
- @Around后置
- @After
6) 创建代理
1. 将被代理对象封装成TargetSource
2. 创建代理工厂ProxyFactory对象,ProxyFactory包含目标对象,以及advisors,如果目标对象是接口走jdk动态代理,否则走cglib动态代理
3. 比如我们是jdk动态代理,JdkDynamicAopProxy实现了InvocationHandler接口
4. 然后调用JdkDynamicAopProxy类的getProxy方法,这里面会生成动态代理:
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
7) 在调用目标类的方法的时候,实际上会调用JdkDynamicAopProxy的invoke方法
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
//如果索引的值等于拦截器集合的长度-1的值就终止调用
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.
//调用MethodInterceptor的invoke方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}