一.AOP的概念
1.概念:AOP即面向切面编程,与OOP(面向对象编程)相辅相成。即将程序中重复代码抽取出来,在程序执行时利用动态代理技术,运用这些代码。
OOP中程序的基本单元是类,AOP中程序的基本单元是切面
2.优势
减少代码重复、维护方便、提高开发效率
3.AOP术语
(1)切面:切入点+通知
(2)连接点:目标对象中有可能被增强的方法。目标对象中所有的方法都是连接点
(3)切入点:目标对象中已经被增强的方法
(4)通知:增强的代码
(5)代理:将通知织入到目标对象中形成代理对象
(6)目标对象:被代理的对象
(7)织入:将通知应用到切入点的过程
4.实现方式
jdk动态代理+cglib动态代理
二.代理模式
目标类和代理类要有相同的行为,代理对象对目标对象的功能进行增强
代理模式中的角色有:
- 业务接口:目标类和代理类共同去实现的
- 目标类:业务逻辑的具体执行者
- 代理类:对目标类的功能进行增强
- 测试类:通过访问代理类中的方法,就可访问到所有方法
三.静态代理
特点:在运行之前创建代理类,通过代理类产生代理对象。目标类和代理类实现同一接口。
静态代理例子:
观众去看演唱会,其中布置舞台和卖票都由经纪公司去实现,而唱歌跳舞由歌手实现。这就是静态代理,公司是代理类,歌手是目标类,他们共同实现的是完成演出。
业务接口:
//业务接口
public interface Show {
public void show();
}
目标类:
//目标类
@Data
@AllArgsConstructor
public class Singer implements Show{
private String name;
@Override
public void show() {
System.out.println(this.name+":唱歌");
System.out.println(this.name+":跳舞");
}
}
@AllArgsConstructor:使用此注解相当于直接构造该类的有参构造器
代理类:
//代理类
@Data
@AllArgsConstructor
public class Company implements Show{
private String name;
//代理的目标对象
private Show target;
@Override
public void show() {
System.out.println(this.name+":布置");
System.out.println(this.name+":卖票");
target.show();
}
}
测试类:
//测试类
public class User {
public static void main(String[] args) {
Show target = new Singer("偶像");
Show proxy = new Company("经纪公司",target);
proxy.show();
}
}
四.动态代理
1.JDK动态代理
特点:在程序运行中产生一个代理类,并通过该类产生代理对象。
(1)动态代理借助java.lang.reflect.Proxy类,调用该类的newProxyInstance()方法自动生成代理类。
newProxyInstance(loader,Interface,InvocationHandler):
三个参数分别是:
- 目标类的类加载器,用于加载代理类
- 目标类实现的接口,用于给代理类实现
- InvocationHandler的实例
(2)通过实现java.lang.reflect.InvocationHandler接口的唯一方法invoke()来处理代理类的方法
invoke(proxy,nethod,args)
- proxy:产生的代理对象
- method:目标类中的方法
- args:目标对象的方法中的参数
动态代理实现上述静态代理的例子:
业务接口和目标类同上
方法一:
业务处理类:
//业务处理类
@AllArgsConstructor
public class HandlerImpl implements InvocationHandler{
private Singer singer;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("经纪公司:布景");
System.out.println("经纪公司:卖票");
Object result = method.invoke(singer, args);
System.out.println("经纪公司:收拾");
return result;
}
}
测试类:
//测试类
public class User {
public static void main(String[] args) {
//创建目标对象
Singer singer = new Singer("偶像");
//创建业务处理对象
HandlerImpl handler = new HandlerImpl(singer);
//创建代理对象
Show proxy = (Show)Proxy.newProxyInstance(
//目标对象的类加载器
Singer.class.getClassLoader(),
//目标对象实现的接口
Singer.class.getInterfaces(),
//业务处理类的实例
handler);
proxy.show();
}
}
@AllArgsConstructor:该注解意味着创建了有参构造器
方法二:匿名内部类写法
//测试类
public class User {
public static void main(String[] args) {
//创建目标对象
Singer singer = new Singer("偶像");
//创建代理对象
Show proxy = (Show)Proxy.newProxyInstance(
//目标对象的类加载器
Singer.class.getClassLoader(),
//目标对象实现的接口
Singer.class.getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("经纪公司:布景");
System.out.println("经纪公司:卖票");
//通过反射的方式调用目标对象中的方法,并接收执行结果
Object object = method.invoke(singer, args);
System.out.println("经纪公司:收尾");
return object;
}
});
proxy.show();
}
}
当代理对象执行方法的时候,invoke()才能被执行
2.cglib动态代理
jdk动态代理必须实现接口,对于没有实现接口的目标类,只能采用cglib动态代理。
实现原理:目标类是父类,代理类是子类。代理类继承了目标类,重写了目标类中的方法。代理对象在调用目标方法时,实际调用的是重写的方法intercept()
asm包和cglib包可能因为版本不兼容报错,可直接用spring-core包,这里已经继承了cglib所需的jar包
(1)MethodInterceptor接口,重写该接口的intercept()方法。该方法会在代理对象执行目标方法时被调用
intercept(Object proxy,Method method,Object args,MethodProxy methodProxy)
- proxy:cgllib根据指定的父类产生的代理对象
- method:目标对象中的方法
- args:方法参数
- methodProxy:方法的代理对象,用于执行父类的方法
invokeSuper(proxy,args)
调用该方法即调用的是proxy类的父类的方法
(2)Enhancer类相当于jdk中的Proxy类,都是用来生成代理对象的。
Enhancer类的create()用来创建代理对象
目标类:
//目标类
@AllArgsConstructor
public class Student {
public void saveAnddelete() {
System.out.println("执行保存学生操作");
System.out.println("执行删除学生操作");
}
方法拦截器:
//方法拦截器
public class CglibProxy implements MethodInterceptor{
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("开启事务");
//调用目标类中的目标方法
Object obj = methodProxy.invokeSuper(proxy, args);
System.out.println("关闭事务");
return obj;
}
}
测试类:
//测试类
public class Test {
public static void main(String[] args) {
//创建增强类对象,相当于jdk中的代理类
Enhancer enhancer = new Enhancer();
//设置代理类的父类
enhancer.setSuperclass(Student.class);
//设置回调对象
enhancer.setCallback(new CglibProxy());
//creat()方法是创建代理对象
Student proxy = (Student)enhancer.create();
proxy.saveAnddelete();
}
}