AOP
面向切面编程:对业务的各个部分进行隔离,降低耦合度,提高程序的可重复利用性,同时提高开发效率,即不修改原有代码的基础下,拓展新的功能。
底层原理(动态代理)
术语:
- 连接点:理论上可以被增强的方法
- 切入点:实际被增强的方法
- 通知(增强):方法中增加的部分:type
1. 前置通知:方法之前执行
2. 后置通知:方法之后执行
3. 环绕通知:方法前后都有
4. 异常通知:方法异常后执行
5. 最终通知:类比try catch finally - 切面:一个动作:将通知应用于切入点的过程
有接口:JDK动态代理
创建拓展功能的接口的代理对象
调用newProxuInstance方法
参数一:类的加载器
参数二:增强方法所在的类,此类为接口的实现类
参数三:实现InvocationHandler这个接口,创建代理对象,写增强的方法
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
UserDaoImpl u1 = new UserDaoImpl();
//返回的代理类可以给被当作被代理类使用---返回的类型class jdk.proxy1.$Proxy0,需要强转
UserDao o = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(u1));
String a = o.update("1");
int s = o.adds(1,2);
u1.adds(1,2);
}
}
class UserDaoProxy implements InvocationHandler{
//传入被代理的目标传入
private Object o;
public UserDaoProxy(Object o){
this.o = o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法执行之前
System.out.println("此处可以在"+method.getName()+"方法之前扩展");
//被增强的方法
Object invoke = method.invoke(o, args);
//方法执行之前
System.out.println("此处可以在"+method.getName()+"方法之后扩展");
return invoke;
}
}
此处可以在update方法之前扩展
原update方法执行ing…
此处可以在update方法之后扩展
此处可以在adds方法之前扩展
原adds方法执行ing…
此处可以在adds方法之后扩展
原adds方法执行ing…
结论:被代理的接口,只有在调用具体方法时才被代理,比如代理的接口中有多个方法,动态代理不会区分代理了哪个方法,代理的是整个接口,只在调用具体方法的时候才会被增强。调谁增强谁。也可以在增强前添加判断通过Mothed.getName实现不同的增强规划
AspectJ
Sprint框架中,通过AspectJ实现AOP操作。
- 基于XML配置文件实现
- 基于注解实现
切入点表达式(确定增强的切入点) :execution(args):args:权限修饰符(*代替)、返回值类型(可以省略)、类的全路径、方法名称、参数列表(..)
具体流程
步骤一:创建被增强类
步骤二:创建增强类(xxProxy)
步骤三:在配置文件中开启注解扫描 ,(复制修改xml文件前面几行context 、aop)
步骤四:使用注解创建被增强类的对象,以及增强类的对象( xxProxy),添加@Component
步骤五:在增强类(xxProxy)上添加@Aspect,并且在增强方法上添加五种通知对应的注解,参数为切入点表达式例如 @Before(切入点表达式)
步骤六:在Spring配置文件中生成代理对象 :<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
执行顺序,
无接口:CGLIB动态代理
创建当前类的子类的代理对象