个人网站的设计与建设论文,基本的网站开发技术路线,宁夏省住房城乡建设厅网站,做网站后台怎么弄aop实现原理简介
首先我们都知道aop的基本原理就是动态代理思想#xff0c;在设计模式之代理模式中有介绍过这两种动态代理的使用与基本原理#xff0c;再次不再叙述。
这里分析的是#xff0c;在spring中是如何基于动态代理的思想实现aop的。为了方便了解接下来的源码分析…aop实现原理简介
首先我们都知道aop的基本原理就是动态代理思想在设计模式之代理模式中有介绍过这两种动态代理的使用与基本原理再次不再叙述。
这里分析的是在spring中是如何基于动态代理的思想实现aop的。为了方便了解接下来的源码分析这里简单化了一个流程图分析aop的基本实现思想。
so基于上面的流程一步步分析spring源码中的aop实现方式。
采用一个简单的aop例子利用基于注解配置方式的切面配置分析一个简单的Before AOP例子。在spring boot下运行以下简单例子。
AOP的advisor和advice配置。
Component
Aspect
public class AopConfig {Pointcut(execution(* com.garine.debug.testcase.model.AopObject..*(..)))public void mypoint(){//切面定义}Before(mypoint())public void doAround() throws Throwable {System.out.println(before logic);}
}AopObject被代理拦截对象。
Component
public class AopObject {public void aoped(){System.out.println(logic);}
}代理实现的处理器(BeanPostProcessor)
首先是第一步内容对我们在AopConfig中的AOP配置内容进行解析并且保存到BeanFactory中这个过程就是解析保存切面信息。
代理实现的源头–AnnotationAwareAspectJAutoProxyCreator
经过一遍的代码跟踪我了解到注解方式的AOP配置都离不开一个类–AnnotationAwareAspectJAutoProxyCreator这个类继承了BeanPostProcessor接口我们都知道BeanPostProcessor的实现类有多个执行处理节点其中一个执行节点就是在Bean实例化之后。也就是在这个时机AnnotationAwareAspectJAutoProxyCreator拦截bean的初始化过程根据提前解析得到的切面信息对bean的方法进行尝试适配如果有匹配则需要进行代理创建。
这里先分析的就是AnnotationAwareAspectJAutoProxyCreator在bean实例化第一次查询所有切面信息时就会解析保存Aop的信息到实例中跟踪以下代码。
AbstractApplicationContext#refresh 上下文初始化主干方法 AbstractApplicationContext#registerBeanPostProcessors 执行实例化并保存所有实现BeanPostProcessor接口的类
按照上面的逻辑registerBeanPostProcessors 会比一般的bean实例化逻辑要早执行因此我们接下来只需要分析AnnotationAwareAspectJAutoProxyCreator的初始化过程。
AnnotationAwareAspectJAutoProxyCreator的继承结构 通过上图可以知道AnnotationAwareAspectJAutoProxyCreator是继承了BeanfactoryAware接口所以在实例化时会执行setFactory方法。而所有切面信息解析的执行者BeanFactoryAspectJAdvisorsBuilderAdapter初始化的时机也是在setFactory方法。
跟踪代码如下。
AbstractAdvisorAutoProxyCreator#setBeanFactory AnnotationAwareAspectJAutoProxyCreator#initBeanFactory
在这个方法里面会新建一个BeanFactoryAspectJAdvisorsBuilderAdapter这个对象会根据Beanfactory内的aop配置信息进行解析保存。但是需要注意此时虽然新建了BeanFactoryAspectJAdvisorsBuilderAdapter对象.但是此时还不会马上解析aop配置需要在第一次个普通bean实例化时才执行解析aop配置。解析的方法就是
BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors会在初次执行AnnotationAwareAspectJAutoProxyCreator调用postProcessBeforeInitialization时开始执行。
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.initBeanFactory(beanFactory);//aspectJAdvisorsBuilder#buildAspectJAdvisors就是解析配置入口this.aspectJAdvisorsBuilder new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}代理对象(Proxy)的创建
解析并缓存切面
上面提到继承结构图中AnnotationAwareAspectJAutoProxyCreator是实现了InstantiationAwareBeanPostProcessor接口的InstantiationAwareBeanPostProcessor接口定义的postProcessBeforeInitialization方法是一个可以对已经注入依赖属性的bean对象实例进行编辑操作的接口会在
AbstractAutowireCapableBeanFactory#doCreateBean AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition) AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation
方法中执行InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation初次初始化缓存切面信息的话就是在这个方法里面。。具体的调用链如上所示。这里的postProcessBeforeInstantiation方法实际上是AnnotationAwareAspectJAutoProxyCreator的实例进行调用AnnotationAwareAspectJAutoProxyCreator实现InstantiationAwareBeanPostProcessor接口。
下面进入InstantiationAwareBeanPostProcessor#postProcessBeforeInitialization方法分析代码。
AbstractAutoProxyCreator#postProcessBeforeInstantiation AspectJAwareAdvisorAutoProxyCreator#shouldSkip 关键代码
进入如下代码AbstractAutoProxyCreator这个实例也就是之前一开始初始化的AnnotationAwareAspectJAutoProxyCreator实例进入实例的shouldSkip 方法 Overrideprotected boolean shouldSkip(Class? beanClass, String beanName) {// TODO: Consider optimization by caching the list of the aspect names//预先解析缓存切面信息ListAdvisor candidateAdvisors findCandidateAdvisors();for (Advisor advisor : candidateAdvisors) {if (advisor instanceof AspectJPointcutAdvisor) {if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {return true;}}}return super.shouldSkip(beanClass, beanName);}AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
方法findCandidateAdvisors代码如下这里是预先解析缓存所有切面advisor信息注意这一步操作是在AbstractAutoProxyCreator#postProcessBeforeInitialization处理也就是开头提到的切面解析操作解析完成就进行缓存。
Override
protected ListAdvisor findCandidateAdvisors() {// Add all the Spring advisors found according to superclass rules.ListAdvisor advisors super.findCandidateAdvisors();// Build Advisors for all AspectJ aspects in the bean factory.//这里就是前面提到的BeanFactoryAspectJAdvisorsBuilder解析所有切面信息的调用点advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());return advisors;
}然后继续在这里先提前看一下是如何解析aop配置的。跟踪BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
public ListAdvisor buildAspectJAdvisors() {ListString aspectNames null;synchronized (this) {aspectNames this.aspectBeanNames;if (aspectNames null) {ListAdvisor advisors new LinkedListAdvisor();aspectNames new LinkedListString();//查询出Beanfactory中所有已经注册的BeanNameString[] beanNames BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);for (String beanName : beanNames) {if (!isEligibleBean(beanName)) {continue;}// We must be careful not to instantiate beans eagerly as in this// case they would be cached by the Spring container but would not// have been weavedClass? beanType this.beanFactory.getType(beanName);if (beanType null) {continue;}//判断Bean是否是切面BeanisAspect方法判断[标注1]if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);AspectMetadata amd new AspectMetadata(beanType, beanName);if (amd.getAjType().getPerClause().getKind() PerClauseKind.SINGLETON) {MetadataAwareAspectInstanceFactory factory new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);//解析aop class的配置包返回Advisor对象[标注2]ListAdvisor classAdvisors this.advisorFactory.getAdvisors(factory);if (this.beanFactory.isSingleton(beanName)) {this.advisorsCache.put(beanName, classAdvisors);}else {this.aspectFactoryCache.put(beanName, factory);}advisors.addAll(classAdvisors);}else {// Per target or per this.if (this.beanFactory.isSingleton(beanName)) {throw new IllegalArgumentException(Bean with name beanName is a singleton, but aspect instantiation model is not singleton);}MetadataAwareAspectInstanceFactory factory new PrototypeAspectInstanceFactory(this.beanFactory, beanName);this.aspectFactoryCache.put(beanName, factory);advisors.addAll(this.advisorFactory.getAdvisors(factory));}}}this.aspectBeanNames aspectNames;return advisors;}}if (aspectNames.isEmpty()) {return Collections.emptyList();}ListAdvisor advisors new LinkedListAdvisor();for (String aspectName : aspectNames) {ListAdvisor cachedAdvisors this.advisorsCache.get(aspectName);if (cachedAdvisors ! null) {advisors.addAll(cachedAdvisors);}else {MetadataAwareAspectInstanceFactory factory this.aspectFactoryCache.get(aspectName);advisors.addAll(this.advisorFactory.getAdvisors(factory));}}return advisors;
}**[标注1]如何判断类是否是aop切面配置类 **
通过以下代码。
Override
public boolean isAspect(Class? clazz) {return (hasAspectAnnotation(clazz) !compiledByAjc(clazz));
}private boolean hasAspectAnnotation(Class? clazz) {//包含Aspect注解return (AnnotationUtils.findAnnotation(clazz, Aspect.class) ! null);
}[标注2]如何解析为Advisor对象
ReflectiveAspectJAdvisorFactory#getAdvisors 遍历所有没被PointCut注解标注的方法也就是遍历切面内容方法 ReflectiveAspectJAdvisorFactory#getAdvisor 处理所有没被PointCut注解标注的方法候选切面内容方法
代码如下。
Override
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect, String aspectName) {validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());//解析判断候选方法是否有BeforeAfterAround等注解如果有就继续执行新建Advisor对象。AspectJExpressionPointcut expressionPointcut getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());if (expressionPointcut null) {return null;}
//创建advisorreturn new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}最终循环解析BeforeAfterAround等标注的方法都会新建一个Advisor对象。新建的Advisor对象都保存在BeanFactoryAspectJAdvisorsBuilder#advisorsCache中当AnnotationAwareAspectJAutoProxyCreator拦截bean的创建过程时从这里面适配是否有切面可用。
这里解析得到的Advisor大概有以下信息。下面的信息中并没有对PointCut注解做处理pointCut属性只得出一个mypoint()此时还不知道Advisor实际对应的拦截表达式。
拦截表达式还是空的会在AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInstantiation第一次执行时解析拦截表达式。
适配切面
在AbstractAutoProxyCreator#postProcessAfterInitialization执行时找到上面AbstractAutoProxyCreator#postProcessBeforeInitialization缓存的所有的切面信息之后是如何进行切面适配从而决定是否需要进行代理对象的创建呢
在调用AbstractAutoProxyCreator#postProcessAfterInitialization方法时进行切面适配并且会根据适配创建代理对象。根据以下调用链。 AbstractAutoProxyCreator#postProcessAfterInitialization AbstractAutoProxyCreator#wrapIfNecessary protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (beanName ! null this.targetSourcedBeans.contains(beanName)) {return bean;}if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// Create proxy if we have advice.//查找匹配切面Object[] specificInterceptors getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors ! DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);//创建代理对象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;
} AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
protected ListAdvisor findEligibleAdvisors(Class? beanClass, String beanName) {//从缓存取出所有切面信息ListAdvisor candidateAdvisors findCandidateAdvisors();//根据advisor信息中的表达式进行方法对class的匹配ListAdvisor eligibleAdvisors findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;
}
此时如果是第一次执行适配方法findAdvisorsThatCanApply的话candidateAdvisors中的拦截表达式还是空的需要进行表达式获取也就是Pointcut的value。spring的操作的在第一次执行findAdvisorsThatCanApply时解析获取拦截表达式的值获得拦截表达式值之后就跟当前class的方法进行匹配看是否需要进行代理。继续往下跟踪代码
AopUtils#canApply(org.springframework.aop.Advisor, java.lang.Class?, boolean) AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class?, boolean) AspectJExpressionPointcut#getClassFilter AspectJExpressionPointcut#checkReadyToMatch
private void checkReadyToMatch() {if (getExpression() null) {throw new IllegalStateException(Must set property expression before attempting to match);}if (this.pointcutExpression null) {this.pointcutClassLoader (this.beanFactory instanceof ConfigurableBeanFactory ?((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :ClassUtils.getDefaultClassLoader());//解析得到拦截表达式例如根据Before的value来关联查询出对应的表达式this.pointcutExpression buildPointcutExpression(this.pointcutClassLoader);}
}
最终解析完之后advisor中的表达式信息结构如下图。包含在pointcut属性中匹配时就根据pointcutExpression循环进行匹配class的方法。有兴趣的可以继续调试看看是如何实现匹配表达式的。
创建代理对象
如果在上面的匹配切面过程中发现适配的切面那就需要进行代理对象的创建了。
我们回到上面的AbstractAutoProxyCreator#wrapIfNecessary主要看代码如下。 // Create proxy if we have advice.//查找匹配切面Object[] specificInterceptors getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors ! DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);//创建代理对象 Object proxy createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}所以继续看
AbstractAutoProxyCreator#createProxy
的创建代理对象方法。设置ProxyFactory创建Proxy需要的一切信息。
protected Object createProxy(Class? beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}//新建代理对象工厂ProxyFactory proxyFactory new ProxyFactory();proxyFactory.copyFrom(this);//设置工厂代理类if (!proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {evaluateProxyInterfaces(beanClass, proxyFactory);}}//设置拦截切面Advisor[] advisors buildAdvisors(beanName, specificInterceptors);for (Advisor advisor : advisors) {proxyFactory.addAdvisor(advisor);}//设置被代理对象proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}
//创建代理对象return proxyFactory.getProxy(getProxyClassLoader());
}下面看ProxyFactory是如何创建代理对象继续跟踪proxyFactory.getProxy(getProxyClassLoader());
public Object getProxy(ClassLoader classLoader) {return createAopProxy().getProxy(classLoader);
}createAopProxy()作用是根据class的种类判断采用的代理方式看如下实现 DefaultAopProxyFactory#createAopProxy 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)) {//采用jdk动态代理必须基于接口return new JdkDynamicAopProxy(config);}//基于cglib实现代理不需要接口return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}
}所以在当前调试的例子中使用cglib代理。所以执行如下代理。
Override
public Object getProxy(ClassLoader classLoader) {//。。。。。。// Configure CGLIB Enhancer...Enhancer enhancer createEnhancer();if (classLoader ! null) {enhancer.setClassLoader(classLoader);if (classLoader instanceof SmartClassLoader ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {enhancer.setUseCache(false);}}enhancer.setSuperclass(proxySuperClass);enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(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 aboveenhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));enhancer.setCallbackTypes(types);// Generate the proxy class and create a proxy instance.//返回一个cglib代理对象return createProxyClassAndInstance(enhancer, callbacks);}catch (CodeGenerationException ex) {//、、、、、、}
}getCallbacks(rootClass);在这个获取回调函数的方法中普通的aop采用的回调函数是如下的方式。
// Choose an aop interceptor (used for AOP calls).
Callback aopInterceptor new DynamicAdvisedInterceptor(this.advised);cglib 的aop回调函数如下。
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Object oldProxy null;boolean setProxyContext false;Class? targetClass null;Object target null;try {//这里注入的advised就是之前创建的ProxyFactory对象if (this.advised.exposeProxy) {// Make invocation available if necessary.oldProxy AopContext.setCurrentProxy(proxy);setProxyContext true;}// May be null. Get as late as possible to minimize the time we// own the target, in case it comes from a pool...target getTarget();if (target ! null) {targetClass target.getClass();}//根据切面信息创建切面内容调用链ListObject chain this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);Object retVal;// Check whether we only have one InvokerInterceptor: that is,// no real advice, but just reflective invocation of the target.if (chain.isEmpty() Modifier.isPublic(method.getModifiers())) {// 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 methodProxy.invoke(target, argsToUse);}else {// We need to create a method invocation...//创建一个方法调用对象具体调用实现没分析Before逻辑大概是先调用切面在反射调用目标方法retVal new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}retVal processReturnType(proxy, target, method, retVal);return retVal;}finally {if (target ! null) {releaseTarget(target);}if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}}
}