AOP
主要用途:
将日志记录、性能统计、安全控制、事务处理、异常处理等代码从业务逻辑代码中剥离出来,通过对这些行为的分离,可以将它们独立到非业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
主要概念:
Aspect(切面):类似于Java中的类声明,在Aspect中会包含着一些Pointcut以及相应的Advice
Joint point(连接点):表示在程序中明确定义的点,典型的包括构造方法调用、字段的设置和获取、方法的调用、方法的执行、异常处理执行、类的初始化,它自身还可以嵌套其它 joint point
Pointcut(切点):提供一组规则来匹配joint point,这些joint point或通过逻辑关系匹配,或是通过通配、正则表达式等方式匹配,它定义了相应的Advice将要发生的地方
Advice(增强):Advice定义了被PointCut匹配的Joint Point具体要做的操作,通过before、after、around来区别是在每个joint point之前、之后还是前后都要执行的代码
Target(目标对象):织入Advice的目标对象
Weaving(织入):将Aspect和其他对象连接起来, 并创建 Adviced object 的过程
JDK动态代理实现
-
创建调用处理器, 调用新建proxy对象中的方法时, 都会调用该接口中的invoke方法
-
获取实现指定接口的代理类Class对象
-
通过反射创建一个代理类对象, InvocationHandler是传入构造方法的参数
final UserDao userDaoImpl = new UserDaoImpl(); final Aspect aspect = new Aspect(); // 1. 创建调用处理器, 调用新建proxy对象中的方法时, 都会调用该接口中的invoke方法 /* * InvocationHandler是被代理对象的调用处理器实现的接口, 每个代理对象都有一个关联的调用处理器, 当代理对象的一个方法被调用时, 该方法调用会被编码并转换为对它的调用处理器的invoke()方法的调用 * Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, * the method invocation is encoded and dispatched to the invoke method of its invocation handler. */ InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy/*被调用代理对象*/, Method method/*代理对象中被调用的方法*/, Object[] args/*调用方法时的参数*/) throws Throwable { aspect.beforeExecute(); // 调用被代理对象方法前执行切面类中的Advice Object obj = method.invoke(userDaoImpl, args); // 最终的方法调用还是由被代理对象userDaoImpl执行 aspect.afterExecute(); // 调用被代理对象方法后执行切面类中的Advice return obj; } }; // 2. 获取实现指定接口的代理类的Class对象 Class proxy = Proxy.getProxyClass(Factory.class.getClassLoader(), UserDao.class); // 3. 通过反射创建一个代理类对象, InvocationHandler是传入构造方法的参数 // UserDao userDaoProxy = (UserDao) proxy.getConstructor(new Class[]{InvocationHandler.class}).newInstance(new Object[]{handler}); // 可变长形参可以传入一个数组 UserDao userDaoProxy = (UserDao) proxy.getConstructor(InvocationHandler.class).newInstance(handler); return userDaoProxy; /* * 以上操作可以用Proxy.newProxyInstance()方法一步完成: * * Object proxyObject = Proxy.newProxyInstance( * Factory.class.getClassLoader(), // 类加载器, 为null表示使用默认的类加载器 * new Class[]{UserDao.class}, // 代理类和被代理类都需要实现的接口, 为可变长参数 * new InvocationHandler() { // 调用处理器, 使用新建的proxy对象调用方法的时, 都会调用该接口中的invoke方法 * @Override * public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { * aspect.beforeExecute(); * Object obj = method.invoke(userDao, args); * aspect.afterExecute(); * * return obj; * } * }); * * return (UserDao) proxyObject; */
Cglib代理实现:
-
创建方法拦截器, 调用目标方法时CGLib会回调MethodInterceptor中的 intercept() 进行拦截, 在该方法中实现增强
-
使用Enhancer为被代理类创建子类, 设置回调方法拦截器
-
创建代理类对象
final UserDaoImpl userDaoImpl = new UserDaoImpl(); final Aspect aspect = new Aspect(); // 1. 创建方法拦截器, 调用目标方法时CGLib会回调MethodInterceptor中的 intercept() 进行拦截, 在该方法中实现增强 MethodInterceptor interceptor = new MethodInterceptor() { @Override public Object intercept(Object object/*CGLib生成的代理类实例*/, Method method/*被调用代理对象方法*/, Object[] args/*参数列表*/, MethodProxy methodProxy/*代理类对方法的代理引用*/) throws Throwable { aspect.beforeExecute(); // 调用被代理对象方法前执行切面类中的Advice Object obj = method.invoke(userDaoImpl, args); // 最终的方法调用由被代理对象userDaoImpl执行 aspect.afterExecute(); // 调用被代理对象方法后执行切面类中的Advice return obj; } }; // 2. 使用Enhancer为被代理类创建子类, 设置回调方法拦截器 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserDaoImpl.class); // Enhancer是CGLib中的一个字节码增强器, 可以为被代理类创建子类 enhancer.setCallback(interceptor); // 3. 创建代理类对象 Object proxyObject = enhancer.create(); return (UserDaoImpl) proxyObject;