AOP基本概念
面向切面编程(Aspect-oriented Programming 简称AOPAOP) ,是相对面向对象编程(Object-oriented Programming 简称OOP)的框架,作为OOP的一种功能补充. OOP主要的模块单元是类(class)。而AOP则是切面(aspect)。切面会将诸如事务管理这样跨越多个类型和对象的关注点模块化(在AOP的语义中,这类关注点被称为横切关注点(crosscutting))。
-
切面(Aspect): 指关注点模块化,这个关注点可能会横切多个对象。事务管理是企业级Java应用中有关横切关注点的例子。 在Spring AOP中,切面可以使用通用类基于模式的方式(schema-based approach)或者在普通类中以
@Aspect
注解(@AspectJ 注解方式)来实现。-
切面包含通知,切点,连接点; 映射Spring中,可以理解为加了@Aspect注解的类就是一个切面;
-
-
连接点(Join point): 在程序执行过程中某个特定的点,例如某个方法调用的时间点或者处理异常的时间点。在Spring AOP中,一个连接点总是代表一个方法的执行。
-
所有被增强的方法
-
-
通知(Advice): 在切面的某个特定的连接点上执行的动作。通知有多种类型,包括“around”, “before” and “after”等等。通知的类型将在后面的章节进行讨论。 许多AOP框架,包括Spring在内,都是以拦截器做通知模型的,并维护着一个以连接点为中心的拦截器链。
-
所有的增强逻辑,可以理解为加了@Before,@After 等注解的方法
-
-
切点(Pointcut): 匹配连接点的断言。通知和切点表达式相关联,并在满足这个切点的连接点上运行(例如,当执行某个特定名称的方法时)。切点表达式如何和连接点匹配是AOP的核心:Spring默认使用AspectJ切点语义。
-
切点表达式,可以理解为加了@PointCut注解中 execution(* com.jtfu.demo.service.OrderService.*(..))
-
-
引入(Introduction): 声明额外的方法或者某个类型的字段。Spring允许引入新的接口(以及一个对应的实现)到任何被通知的对象上。例如,可以使用引入来使bean实现
IsModified
接口, 以便简化缓存机制(在AspectJ社区,引入也被称为内部类型声明(inter))。 -
目标对象(Target object): 被一个或者多个切面所通知的对象。也被称作被通知(advised)对象。既然Spring AOP是通过运行时代理实现的,那么这个对象永远是一个被代理(proxied)的对象。
-
被代理的对象
-
-
AOP代理(AOP proxy):AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。
-
代理对象
-
-
织入(Weaving): 把切面连接到其它的应用程序类型或者对象上,并创建一个被被通知的对象的过程。这个过程可以在编译时(例如使用AspectJ编译器)、类加载时或运行时中完成。 Spring和其他纯Java AOP框架一样,是在运行时完成织入的。
-
将通知应用到代理对象中方法的过程可以理解成织入
-
SpringAop实现方式
Spring中将所有的增强封装为一个Advisor对象, 可以理解成Advisor包含了 通知(Advice) 和 切点(PointCut);
接口实现
@Component
public class MyAdvisor implements MethodBeforeAdvice, PointcutAdvisor {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName()+"前置增强");
}
@Override
public Pointcut getPointcut() {
return new MyPointCut();
}
@Override
public Advice getAdvice() {
return this;
}
@Override
public boolean isPerInstance() {
return false;
}
public static class MyPointCut implements Pointcut{
@Override
public ClassFilter getClassFilter() {
//进行Class过滤,
return new ClassFilter() {
@Override
public boolean matches(Class<?> clazz) {
return clazz.equals(UserService.class);
}
};
}
@Override
public MethodMatcher getMethodMatcher() {
//进行Method过滤,
return new MethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return method.getName().equals("test");
}
@Override
public boolean isRuntime() {
return false;
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
return method.getName().equals("test");
}
};
}
}
}
注解实现
@Aspect
@Component
public class LubanAspect {
@Pointcut("execution(* com.jtfu.demo.service.OrderService.*(..))")
public void test() {
}
@Before(value = "test()")
public void before(){
System.err.println("方法执行前调用.....");
}
}
@Import注解
@Import注解可以添加一个Bean到Spring容器中,在Spring源码中 对实现了 ImportSelector,DeferredImportSelector,ImportBeanDefinitionRegistrar 接口的类,有不同的处理逻辑;
解析Advisor
在Spring中想使用Aop功能要先添加 @EnableAspectJAutoProxy 注解,这个注解中又包含 @Import(AspectJAutoProxyRegistrar.class), @Import注解 可以往Spring中添加一个Bean,来看一下AspectJAutoProxyRegistrar 具体执行什么逻辑; 追踪代码 发现往Spring中注册了一个 AnnotationAwareAspectJAutoProxyCreator.class 的Bean,查看它的继承关系;
可以从继承关系图上看到 实现了 BeanPostProcessor, InstantiationAwareBeanPostProcessor,SmartInstantiationAwareBeanPostProcessor 三个Bean的后置处理器;
BeanPostProcessor
postProcessBeforeInitialization 初始化之前调用
postProcessAfterInitialization 初始化之后调用
InstantiationAwareBeanPostProcessor
postProcessBeforeInstantiation 实例化之前调用
postProcessAfterInstantiation 实例化之后调用
postProcessProperties 属性填充后调用
SmartInstantiationAwareBeanPostProcessor
determineCandidateConstructors 推断构造方法时调用
getEarlyBeanReference 提早暴露Bean时调用
通过对SpringIOC 生命周期的了解, 先看postProcessBeforeInstantiation 方法; 在父类 AbstractAutoProxyCreator中调用;
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// advisedBeans中存的是当前这个bean需不需要代理
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 当前bean是否跳过代理
//isInfrastructureClass 判断beanClass是否实现了Advisor 等接口
//判断是否加了@Aspect 注解
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
}
以上的代码逻辑,需要自己去跟一下。 总结为下图:扫描到所有的Advisor 后,判断当前BeanClass 是否应该跳过; 如果不跳过,再去判断 TargetSource ,是否提前生成代理对象; 这里一般都不会生成
2.getEarlyBeanReference(Object bean, String beanName) 提早暴露Bean;可用于解决循环依赖,在这里也可以提早进行AOP代理;
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName); // beanName aService
// 判断
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey); //代理对象
}
3.postProcessAfterInstantiation 什么都没做;
4.postProcessBeforeInitialization 什么都没做;
5.postProcessProperties 什么都没做;
6.postProcessAfterInitialization 正常进行AOP增强的地方,处于SpringIOC生命周期中 初始化完成以后的后置处理器调用逻辑;
@Override
// 正常情况进行AOP的地方
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// earlyProxyReferences中存的是哪些提前进行了AOP的bean,beanName:AOP之前的对象
// 注意earlyProxyReferences中并没有存AOP之后的代理对象 BeanPostProcessor
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 没有提前进行过AOP,则进行AOP
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
// 为什么不返回代理对象呢?
return bean; //
}
wrapIfNecessary(bean, beanName, cacheKey);
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 在当前targetSourcedBeans中存在的bean,表示在实例化之前就产生了代理对象
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 当前这个bean不用被代理
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 先判断当前bean是不是要进行AOP,比如当前bean的类型是Pointcut、Advice、Advisor等那就不需要进行AOP
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 获取当前beanClass所匹配的advisors
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果匹配的advisors不等于null,那么则进行代理,并返回代理对象
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 基于bean对象和Advisor创建代理对象
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;
}
前几步与实例化之前执行的逻辑大致相同,判断当前的BeanClass是否需要被增强;主要逻辑是
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 针对当前bean查找合格的Advisor
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
findEligibleAdvisors(Class<?> beanClass, String beanName)
// 得到所有的Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 进行筛选
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 提供给子类去额外的添加advisor
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 按order进行排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
// 返回匹配的Advisor
return eligibleAdvisors;
List<Advisor> candidateAdvisors = findCandidateAdvisors(); 与上面解析的逻辑完全相同,拿到当前BeanFactory中所有的Advisor,然后遍历Advisors 判断有没有对当前BeanClass合适的切点;可以理解为下图:
经过筛选之后,已经确定BeanClass需要被增强,那么就去创建代理对象;
创建代理对象
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
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());
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); 重新封装Advisor 为 DefaultPointcutAdvisor.class ;
设置到ProxyFactiry中,生成并返回代理对象;
proxyFactory.getProxy(getProxyClassLoader()); 代理对象使用JDK动态代理 或者 CGlib 生成;
如何选择动态代理的方式
@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);
}
}
依据以上代码可以得到结论:1.未实现接口时,使用Cglib代理。 2. 实现接口,未指定isProxyTargetClass=true 时 使用jdk动态代理; 3. 被代理对象是接口 或者 已经是一个代理对象时,使用jdk动态代理
4.指定isProxyTargetClass=true,无论是否实现接口 都使用Cglib动态代理;
以下是jdk动态代理生成代理类的逻辑;通过对jdk动态代理的了解,在进行方法调用时会调用InvocationHandler.invoke()方法。这里传入的是 this,再去追踪invoke方法;
@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);
}
@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;
// 暴露代理对象;
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);
}
}
}
个人理解invoke方法的主要学习点有几个
1. 在使用jdk动态代理时,如果在被代理的方法内,再调用本对象的其他方法,不会有增强效果; 此时就需要获得代理对象来调用方法;
// 暴露代理对象;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
2.责任链的构建,会将所有的Advisor 转成MethodInterceptor类型;
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
3.递归调用责任链 retVal = invocation.proceed(); 会走MethodInterceptor.invoke()方法。 具体细节去代码中看吧,逻辑不方便表示.
@Override
@Nullable
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();
}
//currentInterceptorIndex 默认= -1, 这里++currentInterceptorIndex, 就是取第0个
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
/*这里只有 在Advisor --> pointCut -->MethodMatcher.isRuntime= true 时才会走.*/
// 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);
}
}