SpringAOP的配置简单使用

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增强执行》》》》》》》》》》》》》");
	}
*/

}

  1. 配置扫描和代理在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基于接口的代理将起作用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值