003-AOP-概念及实现原理
AOP 基本概念
(1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得 业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
AOP(底层原理)
a)AOP 底层使用动态代理 ,动态代理有两种情况:
第一种 有接口情况,使用 JDK 动态代理 ;创建接口实现类代理对象,增强类的方法
1 2 3 4 5 6 7 8 9 10
| interface UserDao { public void login(); }
class UserDaoImpl implements UserDao { @Override public void login() { } }
|
第二种 没有接口情况,使用 CGLIB 动态代理;创建子类的代理对象,增强类的方法
1 2 3 4 5 6 7 8 9 10 11 12
| class User { public void add() { } }
class Person extends User { public void add() { super.add(); } }
|
JDK 动态代理(只能代理实现接口的类或者直接代理接口)
1)使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象
1 2 3 4 5 6
|
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
|
2)编写 JDK 动态代理代码
1 2 3 4 5
| public interface UserDao { int add(int a, int b); String insert(String id); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class UserDaoImpl implements UserDao {
@Override public int add(int a, int b) { System.out.println("add execute..."); return a+b; }
@Override public String insert(String id) { System.out.println("insert execute..."); return id; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class UserDaoProxy implements InvocationHandler {
private Object object;
public UserDaoProxy(Object object) { this.object = object; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法之前执行:" + method.getName() + ", 传递参数:" + Arrays.toString(args)); Object result = method.invoke(object, args); System.out.println("方法之后执行:" + result); return result; }
}
|
1 2 3 4 5 6 7 8
| public class JDKProxyFactory {
public static Object getProxy(Object target) { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new UserDaoProxy(target)); }
}
|
1 2 3 4 5 6 7 8 9 10
| public class TestJdkProxy { public static void main(String[] args) { UserDao userDao = (UserDao) JDKProxyFactory.getProxy(new UserDaoImpl()); System.out.println(userDao.add(1, 5)); System.out.println("----------------------------------"); System.out.println(userDao.insert("12334")); } }
|
Cglib 动态代理(可代理未实现任何接口的类)
引入依赖
1 2 3 4 5
| <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
|
1 2 3 4 5 6 7 8 9
| class UserDaoImpl { public int add(int a, int b) { System.out.println("add execute..."); return a+b; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class UserDaoCglibProxy implements MethodInterceptor {
@Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("方法之前执行:" + method.getName() + ", 传递参数:" + Arrays.toString(args)); Object result = methodProxy.invokeSuper(o, args); System.out.println("方法之后执行:" + result); return null; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class CglibProxyFactory {
public static Object getProxy(Class<?> clazz) { Enhancer enhancer = new Enhancer(); enhancer.setClassLoader(clazz.getClassLoader()); enhancer.setSuperclass(clazz); enhancer.setCallback(new UserDaoCglibProxy()); return enhancer.create(); }
}
|
实际使用
1 2 3 4 5 6 7
| public class CglibProxyTest {
public static void main(String[] args) { UserDaoImpl userDao = (UserDaoImpl) CglibProxyFactory.getProxy(UserDaoImpl.class); userDao.add(1, 4); } }
|
输出
1 2 3
| 方法之前执行:add, 传递参数:[1, 4] add execute... 方法之后执行:5
|
AOP术语
1 2 3 4 5 6
| class User { void add(); void update(); void select(); void delete(); }
|
连接点
类里面可以增强的方法称为连接点
切入点
类里实际被增强的方法
通知(增强)
实际增强的逻辑部分
通知类型:
- 前置通知:在目标方法前执行的通知(增强)
- 后置通知:在目标方法后执行的通知(增强)
- 环绕通知:在目标方法前后都执行的通知(增强)
- 异常通知:在目标方法出现异常执行的通知(增强)
- 最终通知:在目标方法执行完都会执行(相当于finally)的通知(增强)
通知执行顺序:进入环绕通知 > 前置通知 > 退出环绕通知 > 后置通知 > 最终通知,异常通知出现异常就会执行
切面
把通知应用到切入点的过程
AOP操作
1、Spring框架一般都是基于AspectJ实现AOP操作
AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring一起使用,进行AOP操作
2、基于AspectJ实现AOP操作
3、切入点表达式
知道对哪个类里面的哪个方法进行增强
1 2 3 4 5 6 7 8 9
| execution([权限修饰符] [返回类型] [类全路径][方法名称]([参数列表])) 权限修饰符可以省略 example: 1. 对cn.ysliu.dao.UserDao类里的add方法进行增强,第一个*表示任何返回类型,..表示任何参数 execution(* cn.ysliu.dao.UserDao.add(..)) 2. 对cn.ysliu.dao.UserDao类里所有方法进行增强 execution(* cn.ysliu.dao.UserDao.*(..)) 3. 对cn.ysliu.dao包下所有类所有方法进行增强 execution(* cn.ysliu.dao.*.*(..))
|