1. AOP是什么?
AOP(Aspect Oriented Programming),面向切面编程。顾明思议就是通过某个切入点(比如方法开始、结束)向某个切面(被切的对象)切入环绕通知(需要切入的逻辑代码)。比如一个类中的所有方法执行前都需要打印日志,那么可以通过AOP的方式来统一实现,而不需要在每个方法中都加入打印日志的代码逻辑。 Spring中可以通过配置或者注解方式来实现统一切入逻辑功能(比如事务)。
2. AOP的使用场景
1) 日志记录、监控优化
2) 权限控制
3) 事务管理
4) 缓存
5) 持久化
.....
3. Spring AOP的实现
Spring AOP实现由两种方式:
1)JDK动态代理:基于Java反射机制实现的(涉及java.lang.reflect包中的Proxy和InvocationHandler)。
2)Cglib动态代理:使用底层字节码技术,生成一个子类来代理父类,即继承被代理类。
代理又分为静态代理和动态代理:
1)静态代理:通过设计一个代理类的方式实现,属于预编译的方式,在程序运行前字节码文件就已经存在了。
2)动态代理:运行时生成字节码对象。
4. JDK动态代理实例
1)定义接口
// 用户服务接口
public interface IUserService {
// 插入用户名方法
void insert(String name);
}
2)定义接口实现类
public class UserServiceImpl implements IUserService {
public void insert(String name) {
System.out.println("插入一条用户记录,用户名为:" + name);
}
}
3)测试:创建动态代理对象,调用代理对象中的方法(回调InvovationHandler接口的实现方法invoke)
public class UserTest {
/**
* Object newProxyInstance(ClassLoader loader, //代理类的类加载器,与被代理类的一致
* Class<?>[] interfaces, //代理类需要实现的接口列表,与被代理类实现的接口一致
* InvocationHandler h)// 运行时调用的方法实际会被拦截执行该接口实现的invoke方法
*/
@Test
public void jdkDynamicProxyTest() {
// 创建需要被代理对象的实例
final IUserService userService = new UserServiceImpl();
// 创建代理对象
IUserService userServiceProxy = (IUserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(),
new Class[]{IUserService.class},
new InvocationHandler() {
/**
* @param proxy 调用该方法的代理实例
* @param method 代理实例调用的接口方法
* @param args 代理实例调用接口方法传递的参数
* @return
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("打印日志......");// AOP 动态代理逻辑
method.invoke(userService, args);// 代表调用该接口实现类的userService实例中的方法
return null;
}
});
userServiceProxy.insert("lucy");
}
}
4) 输出
打印日志......
插入一条用户记录,用户名为:lucy
5. Cglib动态代理实例
1)定义被代理对象(作为cglib动态代理的父类),实现MethodInterceptor接口,实现回调方法intercept()
// 定义代理对象的父类,Cglib需要MethodInterceptor
// 调用父类方法时会被拦截,然后回调intercept方法
public class ProductService implements MethodInterceptor {
public void insert(String productName) {
System.out.println("插入商品名称为:" + productName);
}
/**
*
* @param o 代理对象
* @param method 需要被代理的方法
* @param objects 传递参数数组
* @param methodProxy 代理方法
* @return 返回值
* @throws Throwable
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("打印日志......");
methodProxy.invoke(this, objects);
return null;
}
}
2) 测试:创建Enhancer对象,设置类加载器,动态代理父类,回调对象(实现MethodInterceptor接口的类)
public class ProductTest {
@Test
public void cglibTest() {
ProductService productService = new ProductService();// 创建被代理父类(被代理对象)
Enhancer enhancer = new Enhancer();// 创建Cglib核心对象Enhancer
enhancer.setClassLoader(productService.getClass().getClassLoader());// 设置类加载器
enhancer.setSuperclass(productService.getClass());// 设置代理类继承的父类
enhancer.setCallback(productService);// 设置回调对象(MethodInterceptor实现类对象)
ProductService productServiceProxy = (ProductService) enhancer.create();// 创建代理对象
productServiceProxy.insert("苹果手机");
}
}
3)输出
打印日志......
插入商品名称为:苹果手机