Spring AOP两种使用方式以及如何使用解析

AOP是一种面向切面编程思想,也是面向对象设计(OOP)的一种延伸。

在Spring实现AOP有两种实现方式,一种是采用JDK动态代理实现,另外一种就是采用CGLIB代理实现,Spring是如何实现的在上篇已经讲到了Spring Bean的生命周期以及IOC源码解析

AOP可以做日志记录,或者事务回滚,在Spring的事务使用就是通过AOP进行事务的回滚的

JDK动态代理

这个是属于JDK提供的一种代理方式,需提供接口才能使用,主要用的类有两个:1、Proxy:这个主要是生成接口代理对象;2、InvocationHandler:反射射包下的一个接口,Proxy生成的代理接口对象,调用接口方法就会走InvocationHandler实现类的invoke() 方法

 使用示例:

//创建一个接口
public class UserDao {
    String getUserInfo();
}
//实现一个InvocationHandler接口的实现类
public class MyInvocationHandler implements InvocationHandler {
    

    //需实现的方法
    //proxy 代表当前对象自己,建议不要使用,如果使用的话会反复的调用自己,而调用自己会反复走当前invoke方法,容易出现栈溢出;
    //method 指调用的方法Method;
    //args 调用方法的参数;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args){
        //....
        
        return null;
    }
    
    //获取接口代理对象
    public <T> T getProxy(CLass<T> cls){
        //第一个参数为类加载器,这个可以默认使用当前的AppClassLoader,即使用getClassLoader()方法接口
        //需创建代理对象的接口class数组,
        //invocationHandler的实现类对象,这里调用的是当前对象,调用的时候就会走当前对象的invoke方法
        return (E) Proxy.newProxyInstance(cls.getClassLoader(), new Class<?>[] {cls},this);
    }

}

public static void main(Stirng[] args){

    UserDao dao = new MyInvocationHandler().getProxy(UserDao.class);
    //这样就能获取到了UserDao接口的代理对象了
}

在Spring当中是采用 JdkDynamicAopProxy 这个类实现的,可以去源码里看一下这个类继承了InvocationHandler

CGLIB代理

这个代理就比较厉害了,是通过ASM修改 .class字节码进行实现的,并且不需要接口,具体的组成结构可以去看一下大佬写的这篇CGLIB(Code Generation Library)

使用示例:

        /**
         * CGLIB 代理
         */
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(SpringTest06Service.class);
        enhancer.setCallback(new MethodInterceptor() {
			
			public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
				System.out.println(Thread.currentThread().getName()+"run start...");
				Object result = arg3.invokeSuper(arg0, arg2);
				System.out.println(Thread.currentThread().getName()+"result:"+result);
				System.out.println(Thread.currentThread().getName()+"run end...");
				return result;
			}
		});
        
        service = (SpringTest06Service) enhancer.create();
        System.out.println(service);
        String testAop = service.testAop("aaaaaaaa", "bbbbbbbbbbb");
        System.out.println(testAop);
 

在Spring里面实现的类是 ObjenesisCglibAopProxy 

上面就是两种代理的实现方式,但是在Spring里面是怎么使用的呢

Spring使用AOP

需引入Spring相关的AOP的包

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>5.1.12.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>5.1.12.RELEASE</version>
		</dependency>

在配置类上需开启AOP进行方法拦截,@EnableAspectJAutoProxy 启动AOP代理,这个注解有两个参数

1、proxyTargetClass:这个是指定使用JDK动态代理拦截(false)还是使用CGLIB进行拦截(true),默认为false,

2、exposeProxy:表示是否能够让AopContext访问,默认为false就是不能访问。

源码是怎么解析可以自己去看,这个注解通过使用@Import注入了一个SmartInstantiationAwareBeanPostProcessor的实现类,可以自己调试查看,这里就不具体讲了,有空就在聊聊吧

最后配置相对应的切面拦截类

@Aspect
@Component
public class AopConfig {
	
	private static final Log log = LogFactory.getLog(AopConfig.class);
	//切点,需指定到具体修饰符,具体方法名以及具体参数类型,这里表示所有修饰符,com.test.SpringCoreTest.test06.service这个包下的所有类的所有方法并且参数为两个的类型为String的方法进行拦截
	@Pointcut("execution(* com.test.SpringCoreTest.test06.service.*.*(String,String))")
	public void pointCut() {}
	
    //执行前,位于Around环绕方法前的后面执行
	@Before(value = "pointCut()")
	public void before() {
		System.out.println("方法执行前 @Before ....");
	}
	//执行后,位于Around环绕方法后的后面执行
	@After(value = "pointCut()")
	public void after() {
		System.out.println("方法执行后 @After ....");
	}
	//即将返回执行
	@AfterReturning(value = "pointCut()")
	public void afterReturning() {
		System.out.println("方法执行后返回  @AfterReturning ....");
	}
	//抛出异常执行
	@AfterThrowing(value="pointCut()",throwing="e")
	public void afterThrowing(Exception e) {
		System.out.println("方法执行异常后返回  @AfterThrowing ....");
		System.out.println(e);
	}
	//环绕方法,能够拦截执行参数,并且能够修改
	@Around(value = "pointCut()")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("around方法执行前@Around ....");
		Object obj = joinPoint.proceed();
		System.out.println("around方法执行后@Around ....");
		return obj;
	}
	
}

配置好后,调用拦截的方法就可以触发AOP拦截了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值