一.什么是代理模式?
给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
抽象角色:定义代理角色和真实角色的公共对外方法
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑, 供代理角色调用。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色 的业务逻辑方法来实现抽象方法,并可以附加 自己的操作。
二.代理模式的优势
1.职责清晰:真实的角色就是实现自己的业务逻辑,不用关心其他功能,通过代理实现具体一个事务内的工作。
2.安全性:代理对象可以在客户端和目标对象之间起到中介的作用,起到了保护了目标对象的作用。
3.高扩展性 :通过采代理类调用原来的方法增加工资,对产生的结果进行控制,不需要改变原来的代码,符合Java的开闭原则。
采用代理模式可以有效的将具体的实现与调用方进行解耦,通过面向接口进行编码完全将具体的实现隐藏在内部。
三.代理模式的应用场景
安全代理:屏蔽对真实角色的直接访问。
远程代理:通过代理类处理远程方法调用(RMI).
延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。
例子:Java中为扩展某些类的功能而使用代理;Spring的AOP;RPC实现中使用的调用端调用的代理服务;mybatis中实现拦截器插件等。
四.静态代理与动态代理的区别
1.静态代理是在编译时就将接口、实现类、代理类一股脑儿全部手动完成,所以当我们需要很多的代理,每一个都这么手动的去创建实属浪费时间,而且会有大量的重复代码,此时我们就可以采用动态代理,动态代理可以在程序运行期间根据需要动态的创建代理类及其实例,来完成具体的功能。
五.动态代理的两种方式
一种是JDK反射机制提供的代理,另一种是CGLIB代理。
1.在JDK代理,必须提供接口,而CGLIB则不需要提供接口,他是让生成的代理类继承被代理类。
2.jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的,在运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。
3.cglib代理无需实现接口,通过生成类字节码实现代理,比反射稍快,不存在性能问题,但cglib会继承目标对象,需要重写方法,所以目标对象不能为final类。
六.spring两种代理方式
1. 若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
优点:因为有接口,所以使系统更加松耦合
缺点:为每一个目标类创建接口
2. 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。
缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。
附:ASM 是一个 Java 字节码操控框架。它能够以二进制形式修改已有类或者动态生成类。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。在Mybatis里两种动态代理技术都已经使用了,在Mybatis中通常在延迟加载的时候才会用到CGLIB动态代理。
七.静态代理代码
接口类:
package proxy.staticproxy;
/**
* 接口类
* @author lc
*/
public interface User {
/**
* 保存功能
*/
public void save();
}
目标对象:
package proxy.staticproxy;
/**
* 目标对象
* @author lc
*/
public class UserImpl implements User {
@Override
public void save() {
System.out.println("保存用户全部信息成功。");
}
}
代理对象:
package proxy.staticproxy;
/**
* 代理类
* @author lc
*/
public class UserProxy implements User{
private UserImpl user;
/**
* 在构造方法里把目标类的对象注入
*/
public UserProxy(UserImpl user) {
this.user = user;
}
/**
* 重写save方法,对目标对象进行加工,对目标对象的功能进行加工
*/
@Override
public void save() {
System.out.println("开启事务。");
user.save();
System.out.println("关闭事务。");
}
}
测试类:
package proxy.staticproxy;
/**
* 测试类
* @author lc
*/
public class Test {
public static void main(String[] s) {
//目标对象
UserImpl user = new UserImpl();
//代理对象,把目标对象注入给代理对象
UserProxy userProxy = new UserProxy(user);
//使用目标对象实现功能
System.out.println("使用目标对象实现功能:");
user.save();
//使用代理对象实现功能
System.out.println();
System.out.println("使用代理对象实现功能:");
userProxy.save();
}
}
结果:
八.JDK的动态代理代码
接口类:
package proxy.staticproxy;
/**
* 接口类
* @author lc
*/
public interface User {
/**
* 保存功能
*/
public void save();
}
目标对象:
package proxy.staticproxy;
/**
* 目标对象
* @author lc
*/
public class UserImpl implements User {
@Override
public void save() {
System.out.println("保存用户全部信息成功。");
}
}
代理对象:
package proxy.jdkdynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* jdk实现的动态代理对象
* @author lc
*/
public class JdkUserProxy {
/**
* 目标对象
*/
private Object object;
public JdkUserProxy(Object object) {
this.object = object;
}
//生成代理对象
public Object getProxyInstance() {
/*
* object.getClass().getClassLoader():目标对象的类加载器
* object.getClass().getInterfaces():目标对象的接口类型,jdk是通过接口实现的
* new InvocationHandler():处理器
*/
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开启事务");
// 执行目标对象方法
Object returnValue = method.invoke(object, args);
System.out.println("提交事务");
return null;
}
});
}
}
测试类:
package proxy.jdkdynamicproxy;
import proxy.staticproxy.UserProxy;
/**
* jdk动态代理测试类
* @author lc
*/
public class Test {
public static void main(String[] s) {
//目标对象
UserImpl user = new UserImpl();
/*
* 代理对象,把目标对象注入给代理对象;
* 这里只能用目标对象的接口强制转换,因为得到的代理对象和目标对象继承于同一接口,
* 属于同级类,不能强转(就像狗可以强转成动物,但不能强转成猫)
*/
User jdkUserProxy = (User)new JdkUserProxy(user).getProxyInstance();
//使用目标对象实现功能
System.out.println("使用目标对象实现功能:");
user.save();
//使用代理对象实现功能
System.out.println();
System.out.println("使用代理对象实现功能:");
jdkUserProxy.save();
System.out.println(jdkUserProxy.getClass());
}
}
结果:
九.Cglib包下的动态代理
cglib依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
接口类:
package proxy.staticproxy;
/**
* 接口类
* @author lc
*/
public interface User {
/**
* 保存功能
*/
public void save();
}
目标对象:
package proxy.staticproxy;
/**
* 目标对象
* @author lc
*/
public class UserImpl implements User {
@Override
public void save() {
System.out.println("保存用户全部信息成功。");
}
}
代理对象:
package proxy.cglibdynamicproxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* cglib包下的动态代理
* @author lc
*/
public class CglibUserProxy implements MethodInterceptor {
/**
* 目标对象
*/
private Object object;
public CglibUserProxy(Object object) {
this.object = object;
}
//生成代理对象
public Object getProxyInstance() {
//工具类
Enhancer en = new Enhancer();
//设置父类
en.setSuperclass(object.getClass());
//设置回调函数
en.setCallback(this);
//创建子类对象代理
return en.create();
}
/**
* 重写cglib包下的代理对象增强方法
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开启事务");
// 执行目标对象的方法
Object returnValue = method.invoke(object, objects);
System.out.println("关闭事务");
return null;
}
}
测试类:
package proxy.cglibdynamicproxy;
/**
* cglib包下的动态代理
* @author lc
*/
public class Test {
public static void main(String[] s) {
UserImpl user = new UserImpl();
User cglibUserProxy = (User)new CglibUserProxy(user).getProxyInstance();
//使用目标对象实现功能
System.out.println("使用目标对象实现功能:");
user.save();
//使用代理对象实现功能
System.out.println();
System.out.println("使用代理对象实现功能:");
cglibUserProxy.save();
System.out.println(cglibUserProxy.getClass());
}
}
结果: