一、静态代理
静态代理,代理类和被代理的类实现了同样的接口,只能代理特定的类。
- 定义一个接口
public interface Service {
public void delete();
public void update();
public void insert();
}
- 被代理类
public class StudentServiceImpl implements Service {
@Override
public void delete() {
System.out.println("删除学生信息!!!");
}
@Override
public void update() {
System.out.println("修改学生信息!!!");
}
@Override
public void insert() {
System.out.println("添加学生信息!!!");
}
}
- 代理类
public class StaticProxy implements Service {
private Service service;
public StaticProxy(Service service) {
this.service = service;
}
public void delete() {
open();
service.delete();
commit();
}
public void update() {
open();
service.update();
commit();
}
public void insert() {
open();
service.insert();
commit();
}
public void open(){
System.out.println("开启事务!!!");
}
public void commit(){
System.out.println("提交事务!!!");
}
}
4.测试类
public class Test {
public static void main(String[] args) {
//被代理类
StudentServiceImpl student = new StudentServiceImpl();
//被代理类的代理对象
StaticProxy proxy = new StaticProxy(student);
//通过代理对象调用被代理类的方法
proxy.delete();
}
}
运行结果:
被代理类只需负责自己特定的业务,而代理类则负责业务的扩展,比如执行被代理类的方法前要开启事务,执行之后要提交事务,我们就不需要给每个方法都添加开启事务和提交事务。
代理类就会负责完成这些工作。
静态代理的优缺点:
- 优点:
- 被代理类只需负责核心业务
- 业务逻辑的扩展更加方便
- 通用代码放到代理类中,提高了代码的复用性
缺点:
- 被代理类太多,就会导致工作量变大,开发效率降低
二、动态代理
动态代理,由AOP框架动态生成的一的对象,对象可以作为目标对象使用。
动态代理有两种方式:
- JDK动态代理
- CGLIB代理
2.1 JDK动态代理
基于接口的动态代理,只能为实现了接口的类动态代理对象
- 创建一个接口并创建一个它的实现类并重写它的方法。
- 创建一个类实现InvocationHandler接口,并重写invoke方法
public class JdkDynamicProxy implements InvocationHandler {
//被代理的对象
private Object object;
public JdkDynamicProxy(Object object) {
this.object = object;
}
//产生代理对象,返回代理对象
public Object getProxy(){
//1.获取被代理对象的类加载器
ClassLoader classLoader = object.getClass().getClassLoader();
//2.获取被代理对象实现的所有接口
Class<?>[] interfaces = object.getClass().getInterfaces();
//3.创建代理对象
//classloader:类加载器来定义代理类
//interfaces:代理类实现的接口列表
//this:调度方法调用的调用处理函数
Object o = Proxy.newProxyInstance(classLoader, interfaces,this);
return o;
}
//处理代理实例,返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object invoke = method.invoke(object,args);
return invoke;
}
//定义一个打印日志的方法
public void log(String msg){
System.out.println("执行了"+ msg +"方法!");
}
}
- 测试
public class DynamicProxyTest {
public static void main(String[] args) {
//创建被代理类对象
StudentServiceImpl studentService = new StudentServiceImpl();
//创建代理对象,产生的代理对象可以强转成被代理对象实现的接口类型
JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy(studentService);
Service proxy = (Service) jdkDynamicProxy.getProxy();
//使用代理对象调方法,不会执行调用的方法,而是进入到创建代理对象时指定的invoke方法
//调用的方法作为一个参数,传给invoke方法
proxy.delete();
}
}
运行结果:
2.2 CGLib代理
使用JDK动态代理的对象必须是实现了一个或多个接口的,如果要对没有实现接口的类创建代理对象,就要使用CGLIB代理。
基于类的动态代理—CGlib
- CGLib是一个高性能开源的代码生成包,因在Spring的核心包中已包含CGLib所需要的包,所以不再需要添加依赖。
- 创建一个StudentServiceImpl 类,并添加增删改方法。
- 创建一个类,实现MethodInterceptor接口,并重写intercept方法。
/**
* CGLIB代理
*/
public class CGLibDynamicProxy implements MethodInterceptor {
private Object object;
public CGLibDynamicProxy(Object object) {
this.object = object;
}
//创建并返回代理对象
//该代理对象是通过被代理类的子类来创建的
public Object getProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(object.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
log(method.getName());
Object invoke = method.invoke(object, args);
return invoke;
}
//定义一个打印日志的方法
public void log(String msg){
System.out.println("执行了"+ msg +"方法!");
}
}
- 测试
public class DynamicProxyTest {
public static void main(String[] args) {
//创建被代理类对象
StudentServiceImpl studentService = new StudentServiceImpl();
//创建代理对象,产生的代理对象可以强转成被代理类类型
CGLibDynamicProxy cgLibDynamicProxy = new CGLibDynamicProxy(studentService);
StudentServiceImpl proxy = (StudentServiceImpl) cgLibDynamicProxy.getProxy();
//使用代理对象调方法,不会执行调用的方法,而是进入到创建代理对象时指定的intercept方法
//将调用的方法以及方法中的参数传给intercept方法
proxy.insert();
}
}
运行结果:
动态代理的优点:
- 被代理类只需负责核心业务;
- 业务逻辑的扩展更加方便;
- 通用代码放到代理类中,提高了代码的复用性;
- 一个动态代理 , 一般代理某一类业务;
- 一个动态代理可以代理多个类,代理的是接口。