1.spring AOP相关的核心API接口定义
关于AOP概念
Aspect:方面
一个模块化的关于点
Join point:连接点
程序中的一个执行点(比如执行方法、执行构造器)
Advice: 通知
在特定的连接上的特定时机的特定行为
Pointcut:切入点
用来匹配符合要求的连接点(用于配合通知使用,来控制在哪些连接点执行通知的行为)
Introduction:引入
为目标增加额外的方法或者字段
Target object:目标对象
被一个或者多个方面通知的目标对象(要增强的目标)
AOP proxy:AOP代理
用来实现方面约定,由框架创建的代理对象
Weaving:织入
连接方面与目标对象。
分为编译期织入、加载期织入或者运行时织入
Spring AOP框架与Java的AOP框架一样都是运行时织入
关于通知的类型:
Before advice:
前置通知
After returning advice:
正常返回通知
After throwing advice:
异常返回通知
After (finally) advice:
不管正常还是异常都会通知到的最终通知
Around advice:
环绕通知
1.1. Pointcut 切入点
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
Pointcut TRUE = TruePointcut.INSTANCE;
}
切点点接口是由ClassFilter 与 MethodMatcher 组合而成
通过查看ClassFilter与MethodMatcher的接口定义,可以得知,ClassFilter的主要负责的是class匹配
MethodMatcher定义了静态匹配与动态匹配,动态指的是方法运行时的参数。
ClassFilter
@FunctionalInterface
public interface ClassFilter {
boolean matches(Class<?> clazz);
ClassFilter TRUE = TrueClassFilter.INSTANCE;
}
MethodMatcher
public interface MethodMatcher {
boolean matches(Method method, @Nullable Class<?> targetClass);
boolean isRuntime();
boolean matches(Method method, @Nullable Class<?> targetClass, Object... args);
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
因此Poincut 主要是描述了针对哪些类的\哪些方法的\哪些参数来进行AOP增强
1.2. Advice 通知
通过Advice接口可以看到它只是一个标记接口,并未定义任何方法。
所有类型的通知,都会继承自该接口。
public interface Advice {
}
接口体系
根据接口名称 可以大致了解到,spring的几大通知类型
1.Interceptor 拦截环绕通知
public interface Interceptor extends Advice {
}
2.BeforeAdvice 前置通知
public interface BeforeAdvice extends Advice {
}
3.ThrowsAdvice 异常返回通知
public interface ThrowsAdvice extends AfterAdvice {
}
4.AfterReturning 正常返回通知
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
5.IntroductionAdvice 引入通知
public interface IntroductionInterceptor extends MethodInterceptor , DynamicIntroductionAdvice {
}
再向下细分的话,就是方法的通知,还是构造器的通知.
spring中没有实现字段访问的通知,因为字段访问可以通过setter、getter方法通知来代替
1.3.Joinpoint 连接点
使用AOP各种通知时,会需要对切入对象进行最终执行,那么这个切入对象的定义就是连接点的概念。
下面查看基于方法的环绕通知MethodInterceptor的定义。
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
MethodInvocation 就是方法环绕通知的连接点。
下面继续查看连接点接口的定义
Joinpoint接口 主要定义了连接点的基本操作
1.执行
2.获取连接目标对象
3.获取连接目标
public interface Joinpoint {
Object proceed() throws Throwable;
Object getThis();
AccessibleObject getStaticPart();
}
关于JoinPoin的子接口
Invocation
定义了获取可执行目标执行参数的接口
public interface Invocation extends Joinpoint {
Object[] getArguments();
}
ConstructorInvocation
具体的关于构造器的连接点定义
Joinpoint.getStaticPart() 与 这里的getConstructor返回同样的结果,
这个接口的作用是返回值更友好,无须自行强转了
public interface ConstructorInvocation extends Invocation {
Constructor<?> getConstructor();
}
MethodInvocation
具体的关于方法的连接点定义
Joinpoint.getStaticPart() 与 这里的getMethod返回同样的结果,
这个接口的作用是返回值更友好,无须自行强转了
public interface MethodInvocation extends Invocation {
Method getMethod();
}
1.4.Advisor 对方面对象的包装接口
public interface Advisor {
Advice EMPTY_ADVICE = new Advice() {};
Advice getAdvice();
boolean isPerInstance();
}
从接口可以看出该接口的存在的目的就是作为Advice的Holder而存在。
它有两个直接子接口,分别是:
public interface PointcutAdvisor extends Advisor {
Pointcut getPointcut();
}
public interface IntroductionAdvisor extends Advisor , IntroductionInfo {
ClassFilter getClassFilter();
void validateInterfaces() throws IllegalArgumentException;
}
PointcutAdvisor定义了Advice与Pointcut组合使用的场景
IntroductionAdvisor是对引入通知实现基本定义,包括引入的接口信息,而引入通知是向某个实例中引入新的方法,因此
不存在对方法匹配的MethodMatcher,只需要匹配类ClassFilter
2.spring aop的实现
上面查看了 有关spring aop的基本概念定义的相关接口
现在对 spring aop是如果与实例进行关联织入的,进行源码查看分析。
在org.springframework.aop.config.AopNamespaceHandler定义了关于xml方式配置的有关aop namespace下的BeanDefinitionParser
public class AopNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init () {
registerBeanDefinitionParser("config" , new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy" , new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy" , new ScopedProxyBeanDefinitionDecorator());
registerBeanDefinitionParser("spring-configured" , new SpringConfiguredBeanDefinitionParser());
}
}
关于aop的配置,主要是配置:
1.通知
2.切入点
3.方面 即 通知 + 切入点
有了切入点就知道需要对什么目标进行aop增强,
有了通知就知道了aop增强的内容
具体的配置细节这里就不作详细查看了。
接下查看spring是怎么创建代理对象的。
class ConfigBeanDefinitionParser implements BeanDefinitionParser {
@Override
@Nullable
public BeanDefinition parse (Element element, ParserContext parserContext) {
configureAutoProxyCreator(parserContext, element);
}
private void configureAutoProxyCreator (ParserContext parserContext, Element element) {
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}
}
在AopNamespaceUtils对ProxyCreator进行注册配置
AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement))
接下来查看AopConfigUtils中的registerAspectJAutoProxyCreatorIfNecessary看看到底注册的什么类
public abstract class AopConfigUtils {
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator" ;
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>();
static {
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary (BeanDefinitionRegistry registry,
@Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired (Class<?> cls, BeanDefinitionRegistry registry,
@Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null" );
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null ;
}
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;
}
}
可以看到spring创建代理对象的实现主要是InfrastructureAdvisorAutoProxyCreator、AspectJAwareAdvisorAutoProxyCreator、AnnotationAwareAspectJAutoProxyCreator
而spring对aspectj的集成 只是将aspectj的表达式 与 @Aspectj相关注解进行作为aop配置信息进行了支持,实质上spring aop 都是基于的CGLIB 与 JDK的动态代理
而且只能对象交给spring管理的bean进行aop支持,对像 domain 这种不是spring管理的对象,如果想进行方面编程则需要考虑使用full aspectj 进行实现。
而上面三个Creator都继承自AbstractAdvisorAutoProxyCreator 该类主要实现获取方面实例Advisor
AbstractAdvisorAutoProxyCreator继承自AbstractAutoProxyCreator 该类主要是实现代理对象的创建
主要是拓展spring的SmartInstantiationAwareBeanPostProcessor来实现的代理对象创建
下面查看创建类的代码
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor , BeanFactoryAware {
@Override
@Nullable
public Class<?> predictBeanType (Class<?> beanClass, String beanName) {
if (this .proxyTypes.isEmpty()) {
return null ;
}
Object cacheKey = getCacheKey(beanClass, beanName);
return this .proxyTypes.get(cacheKey);
}
@Override
@Nullable
public Constructor<?>[] determineCandidateConstructors (Class<?> beanClass, String beanName) throws BeansException {
return null ;
}
@Override
public Object getEarlyBeanReference (Object bean, String beanName) throws BeansException {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this .earlyProxyReferences.contains(cacheKey)) {
this .earlyProxyReferences.add(cacheKey);
}
return wrapIfNecessary(bean, beanName, cacheKey);
}
@Override
public Object postProcessBeforeInstantiation (Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this .targetSourcedBeans.contains(beanName)) {
if (this .advisedBeans.containsKey(cacheKey)) {
return null ;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this .advisedBeans.put(cacheKey, Boolean.FALSE);
return null ;
}
}
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null ) {
if (StringUtils.hasLength(beanName)) {
this .targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this .proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null ;
}
@Override
public boolean postProcessAfterInstantiation (Object bean, String beanName) {
return true ;
}
@Override
public PropertyValues postProcessPropertyValues (
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
return pvs;
}
@Override
public Object postProcessBeforeInitialization (Object bean, String beanName) {
return bean;
}
@Override
public Object postProcessAfterInitialization (@Nullable Object bean, String beanName) throws BeansException {
if (bean != null ) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this .earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary (Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && 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;
}
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;
}
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 );
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true );
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this .freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true );
}
return proxyFactory.getProxy(getProxyClassLoader());
}
}
关于proxyFactory创建代理对象的方式,主要是根据proxyTargetClass = true / false 来判断使用
org.springframework.aop.framework.CglibAopProxy / org.springframework.aop.framework.JdkDynamicAopProxy
内部主要是创建和配置代理对象,使对应的代理对象与 上面定义的AOP各个通知Advice 进行关联起来。
小结:
在spring 声明式事物中, 如果调用了一个aop的普通方法 在转调事物方法,事物无效
如果下如果调用 a.method1();则不会触发事物,这是因为虽然a对象在spring中是代理对象,在a.method1()时 关于事物的advisor 进行
切入点判断时,方法不符合规则不会进行环绕通知开启提交事物,而在method1()方法中转调 method2时,使用的是this调用,并不是代理
对象调用,因此不会再走代理方法。从而导致事务失效。
class A {
public void method1(){method2();}
@Trasnactional
public void method2(){..}
}
因此在使用spring aop过程中要切记!!!