1.5种通知的使用以及execution表达式的讲解
package person.util;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component //必须有,否则扫描不到
public class Aop {
private Logger logger = LoggerFactory.getLogger(Aop.class);
/* 切点就是作用在哪个业务方法上,第一个*位置是返回值类型;然后是要拦截的包的位置,两个..表示选定包及其子包;
然后是某个类,*表示包中所有类;这个*(..)表示所有方法以及任意返回值*/
@Pointcut("execution( * person..*.*(..))")
public void myPoint() {
logger.info("AOP开启日志》》》》》");
}
@Before("myPoint()")
public void beforeService(JoinPoint joinPoint){
logger.info("*********前置增强处理被执行**************");
logger.info("》》》》》连接点对象名:"+joinPoint.getTarget().getClass().getSimpleName());
logger.info("连接点方法:"+joinPoint.getSignature());
StringBuffer args = new StringBuffer();
if(joinPoint.getArgs().length!=0) {
for(int i = 0; i < joinPoint.getArgs().length; i++){
args.append(joinPoint.getArgs()[i]) ;
if(i<joinPoint.getArgs().length){
args.append(",");
}
}
logger.info("》》》》》》》连接点方法参数值:"+args);
}
}
@After("myPoint()")
public void after(){
logger.info("*******后置通知被执行**********");
}
@AfterThrowing(throwing = "ex",pointcut = "myPoint()")
public void afterThrowing(JoinPoint joinPoint,Exception ex){
logger.info("*****方法异常时执行**********");
logger.info("异常信息:"+ex.getMessage());
}
@AfterReturning(returning = "re",pointcut = "myPoint()")
public void afterReturning(Object re){
logger.info("****方法返回后通知被执行****");
//re是一个数组
logger.info("返回值:"+re);
}
/*
@Around("myPoint()")
public void around(){
logger.info("arround增强执行》》》》》》》》》》》》》");
}
*/
}
- 配置扫描和代理在xml文件中
<!-- 开启Spring注解扫描 -->
<contenxt:component-scan base-package="person.*">
<!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>-->
</contenxt:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true"/>
3.pom中加入aop的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.3.RELEASE</version>
</dependency>
<!--AOP切点的依赖 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.1.3.RELEASE</version>
</dependency>
4.AOP代理的过程:
参考
https://www.jianshu.com/p/cd1e8537c035
源码简单展示过程
(1)AOP的入口是AbstractAutoProxyCreator.postProcessAfterInitialization()方法,在每一个bean实例化之后去匹配判断是否需要生成代理类,生成的也是单例代理类,即这些类也是spring容器启动时就会实例化
public Object postProcessAfterInitialization(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;
}
(2)真正开始代理过程的是AbstractAutoProxyCreator. wrapIfNecessary(Object bean, String beanName, Object cacheKey)
.......前面判断是否需要生成代理
Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
//这个判断是否为空,即该实例bean,是否有连接点,其实还是判断是否需要代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//开始代理
Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
//把真实的bean替换成代理bean
return proxy;
.........后面同样是各种判断
(3)调用 this.createProxy创建代理,一共分两步,设置proxyFactory和调用getProxy返回代理
protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
ProxyFactory proxyFactory = new ProxyFactory();
.......都是设置ProxyFactory的属性
return proxyFactory.getProxy(this.getProxyClassLoader());
}
(4)getProxy接口方法有两种实现cglib和jdk的动态代理,
jdkDynamicAopProxy除了实现AopProxy还实现了jdk中的InvocationHandler
Spring中对默认实现类是org.springframework.aop.framework.DefaultAopProxyFactory,createAopProxy里有决定使用jdk动态代理还是cglib的代码
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
return new JdkDynamicAopProxy(config);
} else {
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.");
} else {
//判断目标类是否是接口,如果是则jdk,否则cglib
return (AopProxy)(targetClass.isInterface() ? new JdkDynamicAopProxy(config) : new ObjenesisCglibAopProxy(config));
}
}
}
5.cglib和jdk动态代理的区别
(1)cglib是spring自己完成的代理操作,而jdk动态代理是jdk内置的,任何人都能写动态代理
(2)jdk动态代理要求目标类必须实现一个接口,但是cglib没有这个要求
(3)jdk动态代理要实现要求代理类implements java.lang.reflect.InvocationHandler这个类,比如springAop的jdkDynamicAopProxy类就实现了该类,但cglib不需要
(4)spring默认使用的是cglib代理,但是如果目标类有接口实现,则会使用jdk动态代理,参考https://blog.csdn.net/wangzhihao1994/article/details/80913210
(5)强制使用cglib ,如果 “proxy-target-class” 属值被设置为 “true”,那么基于类的代理将起作用(这时需要CGLIB库cglib.jar在CLASSPATH中)。如果 “proxy-target-class” 属值被设置为 “false” 或者这个属性被省略,那么标准的JDK基于接口的代理将起作用。