1.AOP是什么
AOP:全称(Aspect Oriented Programming)面向切面编程。
AOP是一种编程思想,指的是在程序运行期间,将某段代码动态切入到指定方法的指定位置进行运行的编程方式。那么这句话是在说什么呢?
假设我们想实现转账功能,转账需要事务管理。我们第一时间会想到在转账的过程中进行事务管理(如开启事务、回滚事务、提交事务),而且都将转账业务和事务管理都封装到一起。
那么下一步我们可能会想到将事务管理封装到一个类中,当需要事务管理的时候,我们手动去调用。这样的确简化了代码,但是这意味着我们执行一个事务都得去手动调用事务管理的方法。
AOP的思想其实就是将事务管理的代码动态切入到转账业务中。
这时候事务管理就是一个切面,面向切面编程就是将切面注入到切入点,将事务管理注入到转账方法中,当执行转账方法中,会为转账方法进行一个事务管理。
这样就可以看出AOP的好处:
- 在程序运行期间,在不修改源码的情况下对方法进行功能增强
- 逻辑清晰,开发核心业务的时候,不必关注增强业务的代码
- 减少重复代码,提高开发效率,便于后期维护
2.AOP底层怎么实现动态切入
一句话就是底层用了动态代理
动态代理的思想就是在不改变目标类的代码前提下,对目标类的方法进行功能增强。
也就是不改变转账业务的前提下,对转账进行事务管理,也就是功能的增强。
3.AOP的两种动态代理方式
①JDK动态代理(基于接口实现)
实现代码如下:
public class JDKProxyFactory {
public static Object getProxy(final Class clazz){
Object proxy = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {
/**
* newProxyInstance:创建代理对象
* 参数:
* ClassLoader loader: 加载目标类的类加载器
* Class<?>[] interfaces:目标类所实现的接口类型(用于做为生成代理对象的模板)
* InvocationHandler h:它是代理对象的功能。
*/
//此方法在代理对象调用任何方法时都会执行
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object o = null;
try {
MyAspect.begin();
o = method.invoke(clazz.newInstance(), args);
MyAspect.commit();
} catch (Exception e) {
MyAspect.rollback();
e.printStackTrace();
} finally {
MyAspect.close();
}
return o;
}
});
return proxy;
}
}
为什么JDK动态代理是基于接口呢?
原因如下:
1、生成的代理类继承了Proxy,由于java是单继承,所以只能实现接口去生成对应的代理对象。
2. 可以在生成代理对象的代码中看到Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() { }
中参数有一个接口。
②Cglib动态代理(基于子类实现)
实现代码如下:
public static Object getProxy(final Class clazz){
//创建一个代理工具类
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(clazz);
//设置回调方法(方法增强)
enhancer.setCallback(new MethodInterceptor() {
//o:代理对象本身的引用
//method:代理对象调用的方法
//objects:方法的参数
//methodProxy:代理对象调用的父类方法(一般不用)
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object oo = null;
try {
MyAspect.begin();
oo = method.invoke(clazz.newInstance(),objects);
MyAspect.commit();
} catch (Exception e) {
MyAspect.rollback();
e.printStackTrace();
} finally {
MyAspect.close();
}
return oo;
}
});
//创建代理对象
Object obj = enhancer.create();
return obj;
}
cdlib动态代理是使用第三方 cglib库,所以要先导入jar包,Maven项目可以在pom.xml文件中添加spring-core-5.1.6.RELEASE依赖。
为什么Cglib动态代理是基于子类呢?
因为cglib实现动态代理方式是对指定的类生成一个子类,覆盖其中的所有方法,也因此代理类或方法不能声明称final的。
4.怎么选择JDK动态代理和Cglib动态代理
如果有接口,默认就会采用jdk动态代理
没有接口,就采用cglib动态代理的方式