目录
1、AOP是什么
2、AOP 的作用及其优势
3、AOP 的底层实现
3.1 JDK动态代理:
3.2 CGLIB动态代理
4、AOP相关概念
5、AOP运行流程图
6、AOP源码解析
6.1 源码解析须知
6.2 注册自动代理创建器
6.3 触发后置处理器
6.4 创建Proxy过程分析
6.5 代理回调增强
6.6 增强器执行
6.7 增强器执行顺序
7、源码总结
AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
直接看一个例子:
业务接口及其实现
public interface UserService {
public void login(String name ,int length);
}
@Service
public class UserServiceImpl implements UserService {
public void login(String name, int length) {
System.out.println("-----我是一个接口,我的信息:用户-" + name + ", 长度-" +length+"-----") ;
}
}
切面类
@Component
@Aspect
public class MyAspect {
@Around("execution(* com.ydt.spring02.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint point) throws Throwable {
System.out.println("-----大哥,我来了-----");
point.proceed();
System.out.println("-----大哥,我走了-----");
}
Spring核心配置
测试
@Test
public void test(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext02.xml");
System.out.println("-------------------------------------------------");
UserService userService = context.getBean(UserService.class);
userService.login("laohu", 18);
System.out.println("-------------------------------------------------");
}
作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强 优势:减少重复代码,提高开发效率,并且便于维护
实际上,AOP 的底层是通过 Spring 提供的的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
Spring AOP 的动态代理技术
JDK 代理 : 基于接口的动态代理技术 Cglib 代理:基于父类的动态代理技术
原理图:
简单代码实现Jdk动态代理和Cglib动态代理
目标类接口
public interface TargetInterface {
public void method();
}
目标类
public class Target implements TargetInterface {
@Override
public void method() {
System.out.println("Target running....");
}
}
动态代理代码
Target target = new Target();
TargetInterface proxyObj = (TargetInterface) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-------执行前增强------");
method.invoke(userService, null);
System.out.println("-------执行后增强------");
return null;
}
}
);
测试执行:
//测试执行,当调用接口的任何方法时,代理对象的代码都无需修改
proxy.method();
目标类
public class Target {
public void method() {
System.out.println("Target running....");
}
}
动态代理代码
Target userService = new Target(); //创建目标对象•
Enhancer enhancer = new Enhancer(); //创建增强器•
enhancer.setSuperclass(Target.class); //设置父类•
enhancer.setCallback(new MethodInterceptor() { //设置回调• @Override•
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
System.out.println("-------执行前增强------");
Object invoke = method.invoke(userService, objects);
System.out.println("-------执行后增强------");
return invoke;
}
});
Target proxy = (Target) enhancer.create(); //创建代理对象
测试执行:
//测试执行,当调用接口的任何方法时,代理对象的代码都无需修改
proxy.method();
Target(目标对象):代理的目标对象
Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知
Aspect(切面):是切入点和通知(引介)的结合
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。
在使用ApplicationContext相关实现类加载bean的时候,会针对所有单例且非懒加载的bean,在构造ApplicationContext的时候就会创建好这些bean,而不会等到使用的时候才去创建。这也就是单例bean默认非懒加载的应用
读者需要了解BeanPostProcessor的相关使用,所有实现BeanPostProcessor接口的类,在初始化bean的时候都会调用这些类的方法,一般用于在bean初始化前或后对bean做一些修改。而AOP的功能实现正式基于此,在bean初始化后创建针对该bean的proxy,然后返回给用户该proxy
结合以上两点,被代理后的bean,实际在ApplicationContext构造完成之后就已经被创建完成,getBean()的操作直接从singletonObjects中获取即可
还记得上一节课我们在解析xml生成遍历文档树的时候,有几个标签不是默认解析的那个地方吗?
/************************************DefaultBeanDefinitionDocumentReader.java*******************************/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
/*default namespace 涉及到的就四个标签
* 、 、 和
*/
parseDefaultElement(ele, delegate);
}
else {
/*
* 其他的属于 custom(拓展)如我们经常会使用到的
* 、 、 、 等
*/
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
但凡注解都有对应的解析器,以用来解析该注解的行为。而且所有的解析器父类为: NamespaceHandlerSupport全局搜索之后可发现(其实你也可以通过调用链来查看)
//org.springframework.aop.config.AopNamespaceHandler类中有对应的解析行为,代码如下:
public class AopNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
//看这里---AOP自动代理Bean定义对象解析器注册
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
看看AspectJAutoProxyBeanDefinitionParser这个解析器是一个啥玩意,他实现了BeanDefinitionParser的parse方法
class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
//开始注册切面注解自动代理创建器
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
return null;
}
//..............................................................
}
通过以上的代码分析,可知,AspectJAutoProxyBeanDefinitionParser主要的功能就是将AnnotationAwareAspectJAutoProxyCreator注册到Spring容器中,把bean交给Spring去托管。AnnotationAwareAspectJAutoProxyCreator的功能我们大胆猜测一下:应该也就是生成对象的代理类的相关功能,这个我们接下来再看。
前面我们说了AOP是基于BeanPostProcessor后置处理器来实现的,通过查看AnnotationAwareAspectJAutoProxyCreator的类层次结构,可知,其实现了BeanPostProcessor接口,实现类为AbstractAutoProxyCreator(这里就是模板模式) :
AbstractAutoProxyCreator主要方法
/*********************************AbstractAutoProxyCreator.java************************/
//前置方法啥也不干,直接返回
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
// 主要看这个方法,在bean初始化之后对生产出的bean进行包装
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//对象实例化、属性注入完成后
// 在initializeBean.applyBeanPostProcessorsAfterInitialization方法中触发
//PS:AnnotationAwareAspectJAutoProxyCreator他爹实现的后置处理器(看下面调用链截图)
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
//生成动态代理对象并且包装起来
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
总结:
1)通过AspectJAutoProxyBeanDefinitionParser类将AnnotationAwareAspectJAutoProxyCreator注册到Spring容器中
2)AnnotationAwareAspectJAutoProxyCreator类的postProcessAfterInitialization()方法将所有有advice的bean重新包装成proxy--->wrapIfNecessary()
6.4.1 进入AOP拦截器
/*********************************AbstractAutoProxyCreator.java************************/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//..........................................
// Create proxy if we have advice.
// 意思就是如果该类有advice(增强,还有可能有多个)则创建proxy,这个里面还对所有增强进行了排序
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 将普通的Bean替换成代理Bean
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
6.4.2 创建代理工厂
/*********************************AbstractAutoProxyCreator.java************************/
protected Object createProxy(Class> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
//保存代理类真实的类型,代理对象执行反射调用的时候还得用
//public static final String ORIGINAL_TARGET_CLASS_ATTRIBUTE =
// Conventions.getQualifiedAttributeName(AutoProxyUtils.class, "originalTargetClass");
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 1.创建ProxyFactory,proxy对象的生产主要就是在ProxyFactory做的(FactoryBean)
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
//判断有没有设置proxy-target-class="true" ,默认为false
if (!proxyFactory.isProxyTargetClass()) {
//配置了还不行,还得判断该Bean是否包含接口
//如果不包含,将来要使用CGLIB方式
//如果包含,还是走JDK方式,并且将接口设置到ProxyFactory代理工厂
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 2.将当前bean适合的advice,重新封装下,封装为Advisor类,然后添加到ProxyFactory中
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
//冻结代理工厂,此时不允许其他线程来对该对象再次代理
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 3.调用getProxy获取bean对应的proxy(命名怎么跟getBean一个德行?)
return proxyFactory.getProxy(getProxyClassLoader());
}
6.4.3 创建何种类型的Proxy
/*********************************ProxyFactory.java************************/
public Object getProxy(@Nullable ClassLoader classLoader) {
//这里有两个方法
//createAopProxy()-->得到代理工具类对象:JdkDynamicAopProxy or ObjenesisCglibAopProxy
//getProxy() --->得到原始bean的代理对象
return createAopProxy().getProxy(classLoader);
}
/*********************************ProxyCreatorSupport.java************************/
// createAopProxy()方法就是决定究竟创建何种类型的proxy
protected final synchronized AopProxy createAopProxy() {
//生成代理对象工具类的计数,避免生成多个
if (!this.active) {
activate();
}
//获取AOP代理工厂并且创建AOP代理工具类(工厂方法模式)
return getAopProxyFactory().createAopProxy(this);
}
/*********************************DefaultAopProxyFactory.java************************/
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//isOptimize() :是否使用优化的代理策略(ThreadLocal线程变量 线程隔离),默认就是false,可以通过expose-proxy="true"改变
//isProxyTargetClass():是否直接代理目标类以及任何接口。默认false,可以通过proxy-target-class="true"改变
//hasNoUserSuppliedProxyInterfaces :确定提供的切面类是否只有SpringProxy指定的接口,或者根本没有指定代理接口
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)) {
//JDK分支
return new JdkDynamicAopProxy(config);
}
//CGLIB分支
return new ObjenesisCglibAopProxy(config);
}
else {
//默认走JDK分支
return new JdkDynamicAopProxy(config);
}
}
6.4.4 生成代理对象
/*********************************JdkDynamicAopProxy.java************************/
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
//得到目标类接口,SpringProxy,Advised,DecoratingProxy,都要进行反向代理
Class>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
//排除equals,hashCode等基类方法的增强,如果有这种增强,直接结束
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//进入JDK动态代理方法,这个就不说了,你不可再改了
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
/*********************************CglibAopProxy.java************************/
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}
try {
//判断是否有增强父类存在
Class> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class> proxySuperClass = rootClass;
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
proxySuperClass = rootClass.getSuperclass();
Class>[] additionalInterfaces = rootClass.getInterfaces();
for (Class> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass, classLoader);
// CGLIB增强器
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
//设置类加载器
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
//设置父类
enhancer.setSuperclass(proxySuperClass);
//需要设置SpringProxy,Advised增强接口,跟JDK动态代理一样,用于反射
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
//设置增强回调
Callback[] callbacks = getCallbacks(rootClass);
Class>[] types = new Class>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// 生成代理类和代理对象,这个就跟之前代理模式一样了
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
/*********************************JdkDynamicAopProxy.java************************/
/**
* 重写了InvocationHandler的invoke回调方法,在此处增强
*/
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 {
// 以下的几个判断,判断目标对象有没有实现Object类的equals、hashCode等Object的方法重写
// 如果没有,不进行增强,直接调用Object里面对应的方法
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;
//如果当前通知暴露了代理,则将当前执行对象使用currentProxy()方法变为当前对象代理
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();
Class> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
//获取当前方法配置的拦截方法链(有可能多个增强),通过适配器获取适handler(多个Interceptor)
List
适配器和handler所在包目录:
CGLIB的回调增强差不太多!
/*********************************CglibAopProxy.java************************/
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
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();
Class> targetClass = (target != null ? target.getClass() : null);
List
/*********************************ReflectiveMethodInvocation.java************************/
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
//从索引为-1的拦截器开始调用,并按序递增
//若拦截器链中的拦截器迭代调用完毕,则就是调用target的函数
//这个函数是通过反射机制完成的,具体实现在AopUtils.invokeJoinpointUsingReflection方法中
return invokeJoinpoint();
}
//获取配置的Advice
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)) {
//调用拦截器的执行方法,拦截器执行拦截逻辑后继续调用目标方法的proceed()方法
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.
//如果是一个interceptor,直接调用这个interceptor对应的方法,
// 进入各种通知过滤器:*AdviceInterceptor和事务过滤器TransactionInterceptor(适配器模式)
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
依次遍历拦截器链的每个元素,然后调用其实现,将真正调用工作委托给各个增强器
我们知道增强其执行顺序是这样的:
现在我们来进行源码调试看看:
纵观以上过程可知:实际就是为bean创建一个proxy,JDK Proxy或者CGLIB Proxy,然后在调用bean的方法时,会通过proxy来反射调用bean方法,通过执行代理回调来进行功能增强!
1:默认 ExposeInvocationInterceptor 2:异常通知 AspectJAfterThrowingAdvice 3:返回通知 AspectJAfterReturningAdvice->AfterReturningAdviceInterceptor 4:后置通知 AspectJAfterAdvice 5:环绕通知 AspectJAroundAdvice 6:前置通知 AspectJMethodBeforeAdvice->MethodBeforeAdviceInterceptor
invoke调用顺序为: 1-2-3-4-5(joinPoint.proceed()之前的部分先执行,通过proceed继续递归)-6
那么invoke方法里面各个对应的通知方法执行顺序为: 5的前一部分(因为在invoke方法中已经先执行)–6(递归的最后一层)–目标方法(递归结束执行目标方法)–返回到5的后一部分–返回到4(finally块必会执行)–返回到3(有异常逃过不执行)–返回到2(try块里有异常才执行)–返回到1默认拦截器方法
重点过程可分为:
1)通过AspectJAutoProxyBeanDefinitionParser类将AnnotationAwareAspectJAutoProxyCreator注册到Spring容器中
2)AnnotationAwareAspectJAutoProxyCreator类的postProcessAfterInitialization()方法将所有有advice的bean重新包装成proxy
3)调用bean方法时通过proxy来调用,proxy依次调用增强器的相关方法,来实现方法切入