简介
AOP全称: AspectOriented Programing面向切面编程
使用
启用@AspectJ支持
为了在Spring中配置@Aspect切面,必须启用Spring对@AspectJ切面配置的支持,spring ioc容器中启用AspectJ注解支持,只要在bean配置文件中定义一个xml元素即可:
<!--启用AspectJ对Annotation的支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
当spring ioc容器检测到bean配置文件中的<aop:aspectj-autoproxy>元素时,会自动与AspectJ切面匹配的bean创建代理
切面,通知,切入点
使用
启用@Aspect支持后,切面是带有@AspectJ注解的java类,此切面会被Spring自动识别并用于配置AOP.
定义了一个SecurityHandler 切面来捕捉通用的切入点表达式
package com.tgb.kwy;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
/**
* Description
*
* @author kongwy [email protected]
* @version 1.0
* @date 2018-06-04-21 -27
*/
@Aspect
public class SecurityHandler {
/*定义Pointcut,Pointcut的名称为pointCut(),此方法没有返回值和参数
* 该方法就是一个标识,不进行调用*/
@Pointcut("execution(* com.tgb.kwy.*.*(..))")
private void pointCut(){};
/*定义Advice,表示我们的advice应用到哪些pointcut订阅的joinPoint*/
@Before("pointCut()")
private void doBefore(){
System.out.println("AOP Before Advice----doBefore");
}
}
此时我的目录结构是这样的
applicationContext.xml的内容:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--启用AspectJ对Annotation的支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean id="userManager" class="com.tgb.kwy.UserManagerImpl"/>
<bean id="SecurityHandler" class="com.tgb.kwy.SecurityHandler"></bean>
</beans>
UserManager
package com.tgb.kwy;
/**
* Description
*
* @author kongwy [email protected]
* @version 1.0
* @date 2018-06-04-20 -18
*/
public interface UserManager {
public void addUser(String username, String password);
}
UserManagerImpl
package com.tgb.kwy;
/**
* Description
*
* @author kongwy [email protected]
* @version 1.0
* @date 2018-06-04-20 -28
*/
public class UserManagerImpl implements UserManager{
@Override
public void addUser(String username,String password){
System.out.println("-------UserManagerImpl.add()---");
}
}
此时我们来测试一下:
package com.tgb.kwy;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Description
* @author kongwy [email protected]
* @version 1.0
* @date 2018-06-04-21 -36
*/
public class Client {
public static void main(String[] args) {
BeanFactory factory=new ClassPathXmlApplicationContext("applicationContext.xml");
UserManager userManager=(UserManager) factory.getBean("userManager");
userManager.addUser("zhangsan","123");
}
}
输出内容:
这个就是一个非常简单的测试 可以简单看到aop的使用
而在上面的代码中,我们也看到了AspectJ切入点表达式,是通过方法的签名来匹配各种方法的:
execution(* com.tgb.kwy..(..))
第一个*, 代表任意修饰符及任意返回值
com.tgb.kwy.*代表匹配这个包下面所有的类
后面紧挨的.* ,代表的所有的方法
(..)代表匹配任意数量的参数
上面的测试,我们测的是before
不过在最上面的导图中,我们有看到,他有好几种通知的方式
后置通知,返回通知,异常通知
@Aspect
public class SecurityHandler {
/*定义Pointcut,Pointcut的名称为pointCut(),此方法没有返回值和参数
* 该方法就是一个标识,不进行调用*/
@Pointcut("execution(* com.tgb.kwy.*.*(..))")
private void pointCut(){};
/*定义Advice,表示我们的advice应用到哪些pointcut订阅的joinPoint*/
@Before("pointCut()")
private void doBefore(){
System.out.println("AOP Before Advice----doBefore");
}
@After("pointCut()")
private void doAfter(){
System.out.println("AOP After Advice----doAfter");
}
@AfterReturning(pointcut="pointCut()",returning="returnVal")
public void afterReturn(JoinPoint joinPoint, Object returnVal){
System.out.println("AOP AfterReturning Advice:" + returnVal);
}
@AfterThrowing(pointcut="pointCut()",throwing="error")
public void afterThrowing(JoinPoint joinPoint,Throwable error){
System.out.println("AOP AfterThrowing Advice..." + error);
System.out.println("AfterThrowing...");
}
}
运行结果
环绕通知
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import java.util.Arrays;
/**
* Description
*
* @author kongwy [email protected]
* @version 1.0
* @date 2018-06-04-21 -27
*/
@Aspect
public class SecurityHandler {
/*定义Pointcut,Pointcut的名称为pointCut(),此方法没有返回值和参数
* 该方法就是一个标识,不进行调用*/
@Pointcut("execution(* com.tgb.kwy.*.*(..))")
private void pointCut(){};
/*环绕通知需要携带ProceedingJoinPoint类型的参数,它是joinPoint的子接口,允许控制何时执行,是否执行
*/
@Around("pointCut()")
public void around(ProceedingJoinPoint pjp){
System.out.println("AOP Around before...");
String methodName = pjp.getSignature().getName();
try {
//前置通知,加入对调用方法前的处理逻辑
System.out.println("\"The method \" + methodName + \" begins with \" + Arrays.asList(pjp.getArgs())");
//正常调用目标对象的目标方法,执行被代理的方法,如果忘记写,就会导致通知被执行了,但是目标方法没有被执行
pjp.proceed();
//返回通知,加入对正常调用后的处理逻辑
System.out.println("The method " + methodName + " ends with " + Arrays.asList(pjp.getArgs()));
} catch (Throwable e) {
//异常通知,目标对象的方法调用异常后的处理逻辑
System.out.println("The method " + methodName + " occurs expection : " + e);
e.printStackTrace();
}
//后置通知
System.out.println("The method " + methodName + " ends");
System.out.println("AOP Around after...");
}
}
运行结果
这里追加一下环绕与其他的区别,其实在代码的注释里面,也都写了..
1) 目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知是不能决定的,他们只是在方法的调用前后执行通知而已,即目标方法肯定是要执行的。
2) 环绕通知可以控制返回对象,即你可以返回一个与目标对象完全不同的返回值,虽然这很危险,但是环绕却可以办到。而后置方法是无法办到的,因为他是在目标方法返回值后调用
切面优先级
如果有多个aspect类, 默认无顺序,所以需要自己定义
可以通过实现Ordered接口或者@Order注解指定
使用@Order注解,序号出现在注解中;
@Order(1)
@Aspect
public class SecurityHandler {
......
}
源码分析
advice通知
拿before开刀
先看类的关系图:
MethodBeforeAdvice实现了一个回调函数,也就是说before方法的实现,会在advice中被配置到目标方法后,调用目标方法时被回调.
public interface Advice {
}
public interface BeforeAdvice extends Advice {
}
// 前置增强接口,使用这个前置接口需要实现一个回调函数
public interface MethodBeforeAdvice extends BeforeAdvice {
/**
* 作为回调函数,该方法的实现在Advice中被配置到目标方法后,会调用目标方法时被回调。
* @param method Method对象,是目标方法的反射对象
* @param args 对象数组,包含目标方法的输入参数
* @param target
* @throws Throwable
*/
void before(Method method, Object[] args, Object target) throws Throwable;
}
PointCut切点
public interface Pointcut {
/**
* 获取类过滤器
* Return the ClassFilter for this pointcut.
* @return the ClassFilter (never {@code null})
*/
ClassFilter getClassFilter();
/**
* 获取匹配切入点的方法
* Return the MethodMatcher for this pointcut.
* @return the MethodMatcher (never {@code null})
*/
MethodMatcher getMethodMatcher();
/**
* 总匹配的标准切入点实例
* Canonical Pointcut instance that always matches.
*/
Pointcut TRUE = TruePointcut.INSTANCE;
}
需要返回一个MethodMatcher,所以point的判断功能,具体是通过这个返回方法MethodMatcher来完成的.
我们找关于PointCut的类继承关系,找到了正则表达式切点: JdkRegexpMethodPointcut,那么就可以来了解一下它的实现了
public class JdkRegexpMethodPointcut extends AbstractRegexpMethodPointcut {
/**
* 要编译的正则表达式模式
*/
private Pattern[] compiledPatterns = new Pattern[0];
/**
* 编译时要排除的正则表达式模式
* Compiled form of the exclusion patterns.
*/
private Pattern[] compiledExclusionPatterns = new Pattern[0];
/**
* 将给定的模式字符串数组初始化为编译时的正则表达式模式
* Initialize {@link Pattern Patterns} from the supplied {@code String[]}.
*/
@Override
protected void initPatternRepresentation(String[] patterns) throws PatternSyntaxException {
this.compiledPatterns = compilePatterns(patterns);
}
/**
* 使用正则表达式匹配给定的名称
* Initialize exclusion {@link Pattern Patterns} from the supplied {@code String[]}.
*/
@Override
protected void initExcludedPatternRepresentation(String[] excludedPatterns) throws PatternSyntaxException {
this.compiledExclusionPatterns = compilePatterns(excludedPatterns);
}
/**
* 使用要排除的正则表达式匹配给定的名称
* Returns {@code true} if the {@link Pattern} at index {@code patternIndex}
* matches the supplied candidate {@code String}.
*/
@Override
protected boolean matches(String pattern, int patternIndex) {
Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
return matcher.matches();
}
/**
* 使用要排除的正则表达匹配给定的名称
* Returns {@code true} if the exclusion {@link Pattern} at index {@code patternIndex}
* matches the supplied candidate {@code String}.
*/
@Override
protected boolean matchesExclusion(String candidate, int patternIndex) {
Matcher matcher = this.compiledExclusionPatterns[patternIndex].matcher(candidate);
return matcher.matches();
}
/**
* 将给定的字符串数组编译为正则表达式的模式
* Compiles the supplied {@code String[]} into an array of
* {@link Pattern} objects and returns that array.
*/
private Pattern[] compilePatterns(String[] source) throws PatternSyntaxException {
Pattern[] destination = new Pattern[source.length];
for (int i = 0; i < source.length; i++) {
destination[i] = Pattern.compile(source[i]);
}
return destination;
}
}
所以pointcut切入点,基本功能就是根据正则表达式判断方法名是否匹配的
AOP xml配置
上面测试,我们是使用的注解方式,现在介绍一下,如果使用xml,应该如何配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置bean-->
<bean id="userManager" class="com.tgb.kwy.UserManagerImpl"/>
<!--配置切面bean-->
<bean id="securityHandler" class="com.tgb.kwy.SecurityHandler"></bean>
<!--配置AOP-->
<aop:config>
<!--配置切面及通知-->
<aop:aspect id="securityHandler" ref="securityHandler" order="1">
<!--以add开头的方法-->
<!--<aop:pointcut id="doBefore" expression="execution(* add*(..))"/>-->
<!--com.tgb.kwy包下所有的类所有的方法,参数不定-->
<!--<aop:pointcut id="addAddMethod" expression="execution(* com.tgb.kwy.*.*(..))"></aop:pointcut>-->
<!--配置切点表达式-->
<aop:pointcut id="doBefore" expression="execution(* com.tgb.kwy.*.add*(..)) || execution(* com.tgb.kwy.*.del*(..))"></aop:pointcut>
<!--前置通知-->
<aop:before method="checkSecurity" pointcut-ref="doBefore"/>
</aop:aspect>
</aop:config>
</beans>
代理机制
- spring aop部分使用jdk动态代理,或者CGLIB为目标对象创建代理
- 如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。 若该目标对象没有实现任何接口,则创建一个CGLIB代理。
- 如果希望强制使用CGLIB代理
<aop:config proxy-target-class="true">
<!-- other beans defined here... -->
</aop:config>
代码实验
目录结构
SecurityHandler
package com.tgb.kwy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Description
*动态代理
* @author kongwy [email protected]
* @version 1.0
* @date 2018-06-04-21 -27
*/
public class SecurityHandler implements InvocationHandler {
private Object targetObject;
public Object createProxyInstance(Object targetObject){
this.targetObject=targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method,Object[] args) throws Throwable{
checkSecurity();
/*调用目标方法*/
Object ret=method.invoke(targetObject,args);
return ret;
}
private void checkSecurity(){
System.out.println("----checkSecurity");
}
}
UserManager
package com.tgb.kwy;
/**
* Description
*
* @author kongwy [email protected]
* @version 1.0
* @date 2018-06-04-20 -18
*/
public interface UserManager {
public void addUser(String username,String password);
public void delUser(int userId);
public String findUserById(int userId);
public void modifyUser(int userId,String username,String password);
}
UserManagerImpl
package com.tgb.kwy;
import javax.swing.plaf.PanelUI;
/**
* Description
*
* @author kongwy [email protected]
* @version 1.0
* @date 2018-06-04-20 -28
*/
public class UserManagerImpl implements UserManager{
@Override
public void addUser(String username,String password){
System.out.println("-------UserManagerImpl.add()---");
}
@Override
public void delUser(int userId){
System.out.println("-------UserManagerImpl.add()---");
}
@Override
public String findUserById(int userId){
System.out.println("-------UserManagerImpl.findUserById()---");
return "张三";
}
@Override
public void modifyUser(int userId,String username,String password){
System.out.println("--------UserManagerImpl.modifyUser()---");
}
}
Client
package com.tgb.kwy;
/**
* Description
*动态代理
* @author kongwy [email protected]
* @version 1.0
* @date 2018-06-04-21 -36
*/
public class Client {
public static void main(String[] args) {
SecurityHandler handler=new SecurityHandler();
UserManager userManager=(UserManager) handler.createProxyInstance(new UserManagerImpl());
userManager.addUser("张三","123");
}
}
测试结果
如果不用动态代理, 上面的SecurityHandler就可以不用了, 那么要改变的就是userManager的实现类了
就得这么写了:
package com.tgb.kwy;
/**
* Description
*静态代理
* @author kongwy [email protected]
* @version 1.0
* @date 2018-06-04-21 -13
*/
public class UserManagerImplProxy implements UserManager{
private UserManager userManager;
@Override
public void addUser(String username,String password){
checkSecurity();
userManager.addUser(username,password);
}
@Override
public void delUser(int userId){
checkSecurity();
userManager.delUser(userId);
}
@Override
public String findUserById(int userId){
checkSecurity();
return userManager.findUserById(userId);
}
@Override
public void modifyUser(int userId,String username,String password){
checkSecurity();
userManager.modifyUser(userId,username,password);
}
private void checkSecurity(){
System.out.println("-------checkSecurity-----");
}
}
然后我没添加一个方法, 就得在这个方法里面写上checkSecurity. 是不是很麻烦.
源码
上面也有写类SecurityHandler 实现了InvocationHandler类. 所以动态代理的核心,就是这个类,InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起.那么这个就是AOP的第二部分: 启动代理对象的拦截器来完成各种横切面的织入, 那么第一部分, 需要为目标对象建立代理对象,那么咱们先来聊聊,动态对象如何生成的
动态对象生成
ProxyFactoryBean ,spring应用是通过配置和调用它,来完成任务的,先看一下它的相关类继承关系
- ProxyConfig,共同基类,可以看成有一个数据基类.
- AdvisedSupport的实现中,封装了AOP对通知和通知器的相关操作;子类完成
- ProxyCreatorSupport,创建AOP代理对象的一个辅助类;子类完成
- AspectJProxyFactory,集成spring和AspectJ.适用于需要使用AspectJ 的AOP应用
- ProxyFactoryBean,Spring的AOP应用, 可以在ioc容器中完成声明式配置
- ProxyFactory: Sping的AOP应用,需要使用编程式使用
在ProxyFactoryBean中,1,为target目标对象生成Proxy代理对象.而想得到代理对象,得通过getproxy()方法
我们跳到ProxyFactoryBean类里面看这段代码:
/**
* Return a proxy. Invoked when clients obtain beans from this factory bean.
* Create an instance of the AOP proxy to be returned by this factory.
* The instance will be cached for a singleton, and create on each call to
* {@code getObject()} for a proxy.
* @return a fresh AOP proxy reflecting the current state of this factory
*/
@Override
@Nullable
public Object getObject() throws BeansException {
initializeAdvisorChain();//初始化通知器
if (isSingleton()) {
return getSingletonInstance();//根据定义生成单例proxy
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance(); //根据定义生成prototype的Proxy
}
}
我们继续看getSingletonInstance()
/**
* Return the singleton instance of this class's proxy object,
* lazily creating it if it hasn't been created already.
* @return the shared singleton proxy
*/
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();//这有是一个方法,这个方法就是返回创建代理时使用的目标对象。
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
//获取目标对象class
Class<?> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
//Set the interfaces to be proxied. 设置代理对象接口
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
// Initialize the shared singleton instance.初始化共享单例 setFrozen是父类的方法
super.setFrozen(this.freezeProxy);
//getProxy依旧是ProxyFactory的方法, 而createAopProxy则是ProxyCreatorSupport的方法
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
我们跳进ProxyCreatorSupport方法看看
/**
* Subclasses should call this to get a new AOP proxy. They should <b>not</b>
* create an AOP proxy with {@code this} as an argument.
*/
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
/**
* Return the AopProxyFactory that this ProxyConfig uses.
*/
public AopProxyFactory getAopProxyFactory() {
return this.aopProxyFactory;
}
/**
* Create a new ProxyCreatorSupport instance.
*/
public ProxyCreatorSupport() {
this.aopProxyFactory = new DefaultAopProxyFactory();
}
继续看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.");
//如果targetClass是接口类,使用jdk来生成Proxy
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
//如果不是接口类要生成Proxy,那么使用CGLIB来生成
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
到这里就能看出来,代理对象是jdk或者Cglib生成的
JDK生成AopProxy代理对象过程
上面我们知道了代理对象的生成,是通过Spring封装的JdkDynamicAopProxy类完成的,那么我们就跳到这个类里面,找它的getProxy()
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//这里是调用jdk生成Proxy的地方
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
- 总结一下,代理对象咋生成的?
- 两种代理对象生成方法: 1.ProxyFactory 2.ProxyFactoryBean
- 通过createAopProxy().getProxy() 来获取对应的代理对象, 上面讲的是 ProxyFactoryBean获得代理对象
- 首先调用getSingletonInstance() 这个方法里面是引入了父类ProxyCreatorSupport的方法, 另外这个方法里面还包括了createAopProxy().
- 继续往下走,有一个构造函数,定义了DefaultAopProxyFactory(). 这个类里面的createAopProxy(),默认是调用jdk动态
拦截器
原理:AopProxy封装对象target模板对象之后,ProxyFactoryBean的getObject方法得到的对象,就不在是一个普通的java对象了. 是一个代理对象.这是ProxyFactoryBean中配置的target对象,不会让应用直接调用其方法实现了.所以对target的方法调用时,会先被AopProxy代理对象拦截.jdk生成的代理, 使用的InvocationHandler的invoke回调入口
那么invoke是如何拦截的
还记得上面的这个吧:
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
最后一句话,我们跳进去看:
所以this,指的就是InvocationHandler对象了.InvocationHandler是jdk定义的反射的一个接口,这个接口定义了invoke方法(也就这么一个方法),这个invoke方法是作为jdk proxy代理对象进行拦截的回调入口出现的.
我们看JdkDynamicAopProxy的类图
因为JdkDynamicAopProxy实现了InvocationHandler,所以当Proxy对象的代理方法被调用时,JdkDynamicAopProxy的invoke方法,就会被作为Proxy对象的回调函数被触发
我们看一下invoke方法
/**
* Implementation of {@code InvocationHandler.invoke}.
* <p>Callers will see exactly the exception thrown by the target,
* unless a hook method throws an exception.
*/
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
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. 如果目标对象没有实现Object类的基本方法:equals
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.如果目标对象没有实现Object类的基本方法:hashCode
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.如果没有设定拦截器,那么就直接用target的对应方法
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来实现
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);
}
}
}
上面代码我们看了,如果没有设置拦截器,会对目标对象直接进行调用.对于jdkDynamicAopProxy代理对象,这个对目标对象调用的方法,是通过AopUtils使用反射机制在AopUtils.invokeJoinpointUsingReflection方法中实现的,—上面代码有的,
我们来看一下这个方法
/**
* Invoke the given target via reflection, as part of an AOP method invocation.
* @param target the target object
* @param method the method to invoke
* @param args the arguments for the method
* @return the invocation result, if any
* @throws Throwable if thrown by the target method
* @throws org.springframework.aop.AopInvocationException in case of a reflection error
*/
@Nullable
public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
throws Throwable {
// Use reflection to invoke the method.使用反射调用target对象方法的地方
try {
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.抛出AOP异常,对异常进行转换
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}
拦截器链的调用
AOP实现核心部分
在上面的代码中,我们有看到,对拦截器链调用的是通过ReflectiveMethodInvocation中通过proceed方法实现的.在proceed方法中,我们跳进去看看
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
//从索引为-1的拦截器开始调用,并按顺序递增,如果拦截器链中的拦截器迭代调用完毕,这里开始调用target的函数,这个函数是通过反射机制完成的,具体实现在AopUtils.invokeJoinpointUsingReflection方法中
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//这里沿着定义好的interceptorOrInterceptionAdvice链进行处理
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.这里对拦截器进行动态匹配的判断,如果和前面定义的pointcut匹配,这个advice就会被执行.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.匹配失败,proceed会被递归调用,直到所有拦截器都被运行过为止
// 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对应的方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}