欢迎大家来到IT世界,在知识的湖畔探索吧!
一、什么是aop
Aspect Oriented Programming 面向切面编程,在传统的oop开发过程当中,逻辑是自上而下的,譬如我们实现一个登录功能,浏览器发起http请求到controller,controller负责接受请求,封装参数、验证参数等等,继而把数据传给service,service处理完成之后调用dao,dao操作db后返回;在这个过程当中会产生很多横切性的问题;
比如controller当中的日志记录、比如service当中的权限校验,比如dao当中的事务处理;这些横切性的问题和主业务逻辑是没有关系的,比如日志的记录失败与否并不会影响整个登录逻辑;这些横切的问题如果不去处理会散落在代码的各个地方;面向切面编程就是我们程序员编码只关心横切性问题的抽象;
二、什么spring aop
aop 面向切面编程是一种编程目标,说白了是一个标准;而实现这种编程标准的技术手段有很多;比如:你可以用JDK动态代理来实现aop,也可以使用aspectj这种静态编程技术来实现代理从而实现aop;
spring aop就是实现aop 的一种技术手段;实现aop除了spring aop市面上还有很多其他技术来实现aop;
三、spring aop的核心原理
对于上述的横切性问题spring的做法是把这些问题集中到一个切面(Aspect)当中,然后利用动态代理技术动态增强业务bean;
spring aop的核心技术是JDK动态代理和cglib动态代理,加上spring内部的BeanPostProcessor一起工作,从而达到了对spring当中bean完成增强;
四、spring aop当中的专业术语
Join point
连接点:程序执行当中的一个点,他是一个最终结果,因为spring aop最小连接单位是一个方法,故而一个切点就是一个方法(但是是被连接了的方法);
Pointcut
切点:一组连接点的集合;因为在开发中可能连接点可能会有很多,根据业务和功能的不同会进行分组,切点就是一组连接点的描述(相当于连接点=一条数据,切点等于一张表;一个数据库当中可以存在多张表,表可以有多条数据);
Advice
通知:通知可以从三个维度来理解:1、通知的内容,也就是你增强一个方法的具体业务逻辑,比如日志记录,比如事务操作;2、通知的时机:Before advice、After returning advice、After throwing advice、After (fifinally) advice、Around advice;3、通知的目标,也就是这个通知需要作用到哪个或者哪些连接点上;
Introduction
导入:springAop可以在不修改代码的情况下让某个类强制实现某个接口,并且可以指定接口的默认实现方法;
Target object
目标对象:由于spring aop是借助CGLIB或者JDK动态代理的来实现增强的,目标对象的概念和动态代理当中那个目标对象是同一个概念——被代理的那个对象;
AOP proxy
代理对象:一个被jdk动态代理或者被CGLIB动态代理了之后的对象;
Weaving
织入:一个过程;把切面和应用程序对象连接的过程;
Aspect
切面:上述所有概念在编码过程中存在的类称为切面,切点、连接点、通知等等存在的类称之为一个切面;
五、spring aop开发
1、启用@AspectJ
支持使用Java Confifiguration启用@AspectJ支持要使用Java @Confifiguration启用@AspectJ支持,请添加@EnableAspectJAutoProxy注释
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
欢迎大家来到IT世界,在知识的湖畔探索吧!
使用XML配置启用@AspectJ支持要使用基于xml的配置启用@AspectJ支持,可以使用aop:aspectj-autoproxy元素
<aop:aspectj-autoproxy/>
2、声明一个Aspect
申明一个@Aspect注释类,并且定义成一个bean交给Spring管理
欢迎大家来到IT世界,在知识的湖畔探索吧!@Component
@Aspect
public class UserAspect { }
3、申明一个pointCut
切入点表达式由@Pointcut注释表示。切入点声明由两部分组成:一个签名包含名称和任何参数,以及一个切入点表达式,该表达式确定我们对哪个方法执行感兴趣;
@Pointcut("execution(* transfer(..))")// 切入点表达式
private void anyOldTransfer() {}// 切入点签名
切入点确定感兴趣的 join points(连接点),从而使我们能够控制何时执行通知。Spring AOP只支持Spring bean的方法执行 join points(连接点),所以您可以将切入点看作是匹配Spring bean上方法的执行;
欢迎大家来到IT世界,在知识的湖畔探索吧!/** * 申明Aspect,并且交给spring容器管理 */
@Component
@Aspect
public class UserAspect {
/*** 申明切入点,匹配UserDao所有方法调用
* execution匹配方法执行连接点
* within:将匹配限制为特定类型中的连接点
* args:参数
* target:目标对象
* this:代理对象
*/
@Pointcut("execution(* com.yao.dao.UserDao.*(..))")
public void pintCut(){
System.out.println("point cut");
}
4、申明一个Advice通知
advice通知与pointcut切入点表达式相关联,并在切入点匹配的方法执行@Before之前、@After之后或前后运行;
/*** 申明Aspect,并且交给spring容器管理 */
@Component
@Aspect
public class UserAspect {
/*** 申明切入点,匹配UserDao所有方法调用
* execution匹配方法执行连接点
* within:将匹配限制为特定类型中的连接点
* args:参数
* target:目标对象
* this:代理对象
*/
@Pointcut("execution(* com.yao.dao.UserDao.*(..))")
public void pintCut(){
System.out.println("point cut");
}
/**
* 申明before通知,在pintCut切入点前执行
* 通知与切入点表达式相关联,
* 并在切入点匹配的方法执行之前、之后或前后运行。
* 切入点表达式可以是对指定切入点的简单引用,也可以是在适当位置声明的切入点表达式。
*/
@Before("com.yao.aop.UserAspect.pintCut()")
public void beforeAdvice(){
System.out.println("before");
}
}
六、各种连接点joinPoint的意义
1、execution
用于匹配方法执行 join points连接点,最小粒度方法,在aop中主要使用
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
这里问号表示当前项可以有也可以没有,其中各项的语义如下
modifiers-pattern:方法的可见性,如public,protected;
ret-type-pattern:方法的返回值类型,如int,void等;
declaring-type-pattern:方法所在类的全路径名,如com.spring.Aspect;
name-pattern:方法名,如buisinessService();
param-pattern:方法的参数类型,如java.lang.String;
throws-pattern:方法抛出的异常类型,如java.lang.Exception;
example:
//匹配com.chenss.dao包下任意接口和 类的任意方法
@Pointcut("execution(* com.chenss.dao.*.*(..))")
//匹配com.chenss.dao包下的 任意接口和类的public方法
@Pointcut("execution(public * com.chenss.dao.*.*(..))")
//匹配com.chenss.dao包下的任 意接口和类的public 无方法参数的方法
@Pointcut("execution(public * com.chenss.dao.*.*())")
//匹配 com.chenss.dao包下的任意接口和类的第一个参数为String类型的方法
@Pointcut("execution(* com.chenss.dao.*.*(java.lang.String, ..))")
//匹配 com.chenss.dao包下的任意接口和类的只有一个参数,且参数为String类型的方法
@Pointcut("execution(* com.chenss.dao.*.*(java.lang.String))")
//匹配 com.chenss.dao包下的任意接口和类的只有一个参数,且参数为String类型的方法
@Pointcut("execution(* com.chenss.dao.*.*(java.lang.String))")
//匹配任意的public方法
@Pointcut("execution(public * *(..))")
//匹配任意的以te开头的方法
@Pointcut("execution(* te*(..))")
//匹配 com.chenss.dao.IndexDao接口中任意的方法
@Pointcut("execution(* com.chenss.dao.IndexDao.*(..))")
//匹配com.chenss.dao包及其子包中任 意的方法
@Pointcut("execution(* com.chenss.dao..*.*(..))")
关于这个表达式的详细写法:https://docs.spring.io/spring-framework/docs/current/spring-framework- reference/core.html#aop-pointcuts-examples
由于Spring切面粒度最小是达到方法级别,而execution表达式可以用于明确指定方法返回类型,类名,方法名和参数名等与方法相关的信息,并且在Spring中,大部分需要使用AOP的业务场景也只需要达到方法级别即可,因而execution表达式的使用是最为广泛的;
2、within
该表达式的最小粒度为类;
within与execution相比,粒度更大,仅能实现到包和接口、类级别。而execution可以精确到方法的返回值,参数个数、修饰符、参数类型等;
//匹配com.chenss.dao包中的任意方法
@Pointcut("within(com.chenss.dao.*)")
//匹配com.chenss.dao包及其子包中的任意方法
@Pointcut("within(com.chenss.dao..*)")
3、args
args表达式的作用是匹配指定参数类型和指定参数数量的方法,与包名和类名无关
args同execution不同的地方在于: args匹配的是运行时传递给方法的参数类型 execution(* *(java.io.Serializable))匹配的是方法在声明时指定的方法参数类型;
4、this
JDK代理时,指向接口和代理类proxy,cglib代理时 指向接口和子类(不使用proxy)
5、target
target 指向接口和子类
/**
* 如果配置设置proxyTargetClass=false,或默认为false,则是用JDK代理,否则使用的是CGLIB代理
* JDK代理的实现方式是基于接口实现,代理类继承Proxy,实现接口。
* 而CGLIB继承被代理的类来实现。
* 所以使用target会保证目标不变,关联对象不会受到这个设置的影响。
* 但是使用this对象时,会根据该选项的设置,判断是否能找到对象。
*/
//目标对象,也就是被代理的对象。限制 目标对象为com.chenss.dao.IndexDaoImpl类
@Pointcut("target(com.chenss.dao.IndexDaoImpl)")
//当前对象,也就是代理对象,代理对象时 通过代理目标对象的方式获取新的对象,与原值并非一个
@Pointcut("this(com.chenss.dao.IndexDaoImpl)")
//具有@Chenss的目标对象中的任意方法
@Pointcut("@target(com.chenss.anno.Chenss)")
//等同于@target
@Pointcut("@within(com.chenss.anno.Chenss)")
七、源码分析
我们思考一下我们应该从哪个地方作为入口进行分析?
想一下aop是做什么的,主要是在我们方法执行之前之后去做一些事情,那么肯定得是这个类实例化之后再进行增强;
所以我们只需要找创建类那一块代码,并且是实例化之后的代码
注:如果不知道怎么到这里来的,可以看一下之前的文章,怎么实例化bean,怎么进行属性注入的;
属性填充基本不可能在这个里面,这个只是进行属性注入,那么就是初始化bean的时候会根据aop组件对类生成代理类进行增强;
这里会获取所有待执行的BeanPostProcessors进行执行;
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
其中有一个AbstractAutoProxyCreator用来实现用AOP代理封装每个符合条件的bean,将其委托给指定的拦截器
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean;}
wrapIfNecessary
先找到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;
}
// 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;
}
getAdvicesAndAdvisorsForBean
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
findEligibleAdvisors
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
/** 获取所有的侯选通知 */
List<Advisor> candidateAdvisors = findCandidateAdvisors();
/** 过滤符合条件的通知 */
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
/** 表面此处进行通知排序 */
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
这个方法会先获取所有实现了Advisor接口的类,就是通知类;
再调用buildAspectJAdvisors方法对所有切面进行增强;
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
/** 根据Advisor类型获取所有的实现了Advisor接口的类 */
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
buildAspectJAdvisors方法获取切面及切面相关的通知时只会获取一次,获取一次之后会放入aspectBeanNames切面集合和advisorsCache切面对应的通知集合;
下次获取就直接从缓存中找就好了,这里需要注意的一点是,这里获取出来的时候会进行排序
public List<Advisor> buildAspectJAdvisors() {
/** 当前项目当中所有切面 */
List<String> aspectNames = this.aspectBeanNames;
/** 判断是否等于null */
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
/** 获取当前容器当中所有bean的名字 */
String[] 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 weaved.
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
/** 判断是否为切面 */
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);
/** 找出当前切面的所有通知,并且已进行排序 */
List<Advisor> 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();
}
/** 从缓存中获取 */
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> 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;
}
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new ArrayList<>();
ReflectionUtils.doWithMethods(aspectClass, method -> {
// Exclude pointcuts
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
}, ReflectionUtils.USER_DECLARED_METHODS);
if (methods.size() > 1) {
/** 排序 */
methods.sort(METHOD_COMPARATOR);
}
return methods;
}
我们可以发现他的排序规则是怎样的:Around->Before->After->AfterReturning->AfterThrowing;
private static final Comparator<Method> METHOD_COMPARATOR;
static {
// Note: although @After is ordered before @AfterReturning and @AfterThrowing,
// an @After advice method will actually be invoked after @AfterReturning and
// @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
// invokes proceed() in a `try` block and only invokes the @After advice method
// in a corresponding `finally` block.
Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
new InstanceComparator<>(
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
(Converter<Method, Annotation>) method -> {
AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (ann != null ? ann.getAnnotation() : null);
});
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
}
我们通过findCandidateAdvisors获取到所有的通知,再根据bean进行过滤,注意:这里是先获取所有的通知在进行过滤的,而且这里也有一个排序,那这个排序是干嘛的呢?
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
/** 获取所有的侯选通知 */
List<Advisor> candidateAdvisors = findCandidateAdvisors();
/** 过滤符合条件的通知 */
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
/** 表面此处进行通知排序 */
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
sortAdvisors
其实看到这里我们就不用看了,我之前也分析过这个比较器,如果该类实现了Ordered接口,就通过其方法获取对应的值,否则就获取一个无穷大的值再进行排序;
public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
@Override
@Nullable
protected Integer findOrder(Object obj) {
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
return findOrderFromAnnotation(obj);
}
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
AnnotationAwareOrderComparator.sort(advisors);
return advisors;
}
public static void sort(List<?> list) {
if (list.size() > 1) {
list.sort(INSTANCE);
}
}
找出对应的通知之后再根据通知创建对应的代理类,这里需要注意的是会根据代理工厂利用不同的技术来创建代理类;
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()) {
// Explicit handling of JDK proxy targets (for introduction advice scenarios)
if (Proxy.isProxyClass(beanClass)) {
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// No proxyTargetClass flag enforced, let's apply our default checks...
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
/** 添加aop通知 */
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
/** 通过代理工厂选择是Cglib还是jdk动态代理来生成代理类 */
return proxyFactory.getProxy(getProxyClassLoader());
}
spring一般会尽量选择jdk动态代理来创建代理类
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
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)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
jdk动态代理创建代理类
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
/**
* advised为代理工厂,存储了代理的一些必要参数
* AopProxyUtils.completeProxiedInterfaces:从代理工厂中获取代理对象需要实现的接口集合
*/
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
/** 创建代理对象 */
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
代理类一般是通过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 {
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();
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...
/** 将相关参数封装成ReflectiveMethodInvocation */
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
/** 这个方法是最重要的方法,通过proceed方法依次执行集合中的通知 */
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;
}
/** 如果返回类型为空并且返回类型不为Void则抛出异常 */
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);
}
}
}
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
/** 判断链上还有没有增强器,如果没有则执行目标对象的目标方法 */
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.
/** 执行通知类的处理逻辑 */
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
protected Object invokeJoinpoint() throws Throwable {
/** 执行目标对象的目标方法 */
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
BeforeAdvice通知会先执行自己的增强逻辑,再去执行proceed方法,如果还有待执行的通知则进行执行,没有则执行目标方法;
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
private final MethodBeforeAdvice advice;
/**
* Create a new MethodBeforeAdviceInterceptor for the given advice.
* @param advice the MethodBeforeAdvice to wrap
*/
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
}
AspectJAfterAdvice通知会先执行proceed方法,再执行invokeAdviceMethod他自己的通知方法,proceed方法会再去从通知链里面进行获取,如果没有了就会执行目标方法;
public class AspectJAfterAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
public AspectJAfterAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
@Override
public boolean isBeforeAdvice() {
return false;
}
@Override
public boolean isAfterAdvice() {
return true;
}
}
Advice类型总结:
BeforeAdvice:先执行增强逻辑,再执行proceed方法;
AfterReturningAdvice:执行proceed方法之后进行执行;
AfterAdvice:执行proceed方法和AfterReturningAdvice之后进行执行;
proceed方法:有通知执行通知,没通知执行目标方法;
总结
- SpringAOP不是一种新的AOP实现,使用JDK动态代理和CGLIB动态代理实现;
- SpringAOP配置方式核心是Advisor,可以自定义Advisor,也可以通过AspectJ间接定义Advisor;
- SpringAOP的实现遵循了AOP联盟规范,AOP联盟顶级API接口贯穿了整个AOP过程;
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/22592.html