1,代理模式
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。比较合适的理解就是艺人和经纪人的关系。
代理模式又分为静态代理和动态代理。动态代理常用 JDK 代理和 CGLIB 代理。
2,静态代理
由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口、被代理类、代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
1. 定义一个 Person 接口确认具体行为。
//定义 Person 接口,有一个方法 giveMoney()
public interface Person {
void giveMoney();
}
2. 定义 Student 类,实现具体业务逻辑(被代理类)
public class Student implements Person {
private String name;
public Student(String name){
this.name = name;
}
@Override
public void giveMoney() {
System.out.println(name + "交学费!");
}
}
3. 定义代理类 MonitorProxy ,持有一个 Student 类对象,外界可通过这个类来访问 Student 类的方法。
public class MonitorProxy implements Person {
private Student student;
public MonitorProxy(Student student){
this.student = student;
}
@Override
public void giveMoney() {
System.out.println("我是班长,大家学费交给我了!");
student.giveMoney();
}
}
4. 通过 MonitorProxy 来代理执行 Student 操作。
public class ProxyDemoTest {
public static void main(String[] args) {
MonitorProxy monitor = new MonitorProxy(new Student("张三"));
monitor.giveMoney();
}
}
3,动态代理-JDK
动态代理:在编译期间无法确定需要代理的类。运行期间动态生成代理类。
JDK 动态代理:
在 java 的 java.lang.reflect 包下提供了一个 Proxy 类和一个 InvocationHandler 接口,通过这个类和这个接口可以生成 JDK 动态代理类和动态代理对象。
1,JDK 动态代理 Demo
1. 定义一个接口规范。
public interface Person {
void dance();
void sing();
}
2. 实现接口规范的业务类。
public class Actor implements Person {
private String name;
public Actor(String name){
this.name = name;
}
@Override
public void dance() {
System.out.println(name + "跳个舞!");
}
@Override
public void sing() {
System.out.println(name + "唱个歌!");
}
}
3. 定义处理器,实现 InvocationHandler 接口,invoke 方法定义了代理需要做的事情
public class ProxyHandle<T> implements InvocationHandler {
T target;
public ProxyHandle(T target){
this.target = target;
}
/**
* proxy 表示代理对象
* method 表示正在执行的方法
* args 表示调用方法时的参数
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理执行:" + method.getName() + "方法");
//执行代理方法
Object invoke = method.invoke(target, args);
return invoke;
}
}
4,动态生成代理对象
public class ProxyDemoTest {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Person p = new Actor("张三");
ProxyHandle<Person> personProxyHandle = new ProxyHandle<>(p);
Person o = (Person)Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, personProxyHandle);
o.dance();
o.sing();
//获取动态代理类
//Class<?> proxyClass = Proxy.getProxyClass(null, new Class<?>[]{Person.class});
//获取到代理类,将其输入到文件种
byte[] proxy0s = ProxyGenerator.generateProxyClass("$Proxy0", Actor.class.getInterfaces());
String path = "D:\\gaox\\project\\apz\\demo-base\\src\\main\\java\\com\\demo\\base\\design_partten\\proxy\\code\\com\\demo\\base\\design_partten\\proxy\\dynamics_proxy_jdk\\code\\jdkProxy.class";
try{
FileOutputStream fos = new FileOutputStream(path);
fos.write(proxy0s);
fos.flush();
}catch (Exception e){
}
}
}
2,JDK 代理原理。
1. 首先有一个被代理的实例(Actor)。这个实例必须实现了一个接口(Person)
2. 定义一个调用处理器,持有被代理实例,实现 InvocationHandler 接口,invoke() 方法是代理具体做的事情
public class ProxyHandle<T> implements InvocationHandler {
T target;
public ProxyHandle(T target){
this.target = target;
}
/**
* proxy 表示代理对象
* method 表示正在执行的方法
* args 表示调用方法时的参数
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理执行:" + method.getName() + "方法");
//执行代理方法
Object invoke = method.invoke(target, args);
return invoke;
}
}
3. 创建一个代理类对象。
/**
* loader 一个类加载器
* interfaces 一个 class 对象数组,每个元素都是需要实现的接口
* hander 一个调用处理器,定义了想使用这个代理干什么事
*/
Person o = (Person)Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, personProxyHandle);
newProxyInstance 方法内部创建代理类:
//生成一个代理类
Class<?> cl = getProxyClass0(loader, intfs);
...
//利用反射使用构造方法返回一个代理类实例
final Constructor<?> cons = cl.getConstructor(constructorParams);
return cons.newInstance(new Object[]{h});
此时生成一个默认叫做 $Proxy0 的代理类,拥有 Person 接口的实例方法,访问 $Proxy0 的实例方法,其实是访问执行器的 invoke 方法。
4. 代理类执行对应的方法
通过代理类源码可以看到,其实是执行 ProxyHandle 的 invoke 方法。
3,Proxy 类其他方法。
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler hander)
创建一个代理对象
- loader 一个类加载器
- interfaces 一个 class 对象数组,每个元素都是需要实现的接口
- hander 一个调用处理器,定义了想使用这个代理干什么事
Proxy.isProxyClass(Class<?> cl)
判断一个特定的 class 是否是一个代理类
Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces)
获取一个动态加载类 class
- loader 一个类加载器
- interfaces 一个 class 对象数组,每个元素都是需要实现的接口
ProxyGenerator.generateProxyClass("$Proxy0", Actor.class.getInterfaces())
可以获取到代理 class 的字节数组文件。
4,动态代理-CGLIB
CGLIB 一个强大的,高性能,高质量的 Code 生成类库,它可以在运行期扩展 Java 类与实现 Java 接口
1,CGLIB 动态代理 Demo
1. 定义一个被代理类。(实现不实现接口都无所谓)
public class Actor implements Person {-
private String name;
public Actor(){}
public Actor(String name){
this.name = name;
}
@Override
public void sing() {
System.out.println(name + "唱个歌!");
}
@Override
public void dance() {
System.out.println(name + "跳个舞!");
}
}
2. 定义一个代理类。
public class MyInterceptor implements MethodInterceptor {
private Object target;
public MyInterceptor(Object object){
this.target = object;
}
/**
* @Param o 代理对象
* @Param method 被代理对象的方法
* @Param objects 方法入参
* @Param methodProxy 代理方法
* */
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib before!");
Object invoke = methodProxy.invoke(target, objects);
System.out.println("cglib after!");
return invoke;
}
}
3. CGLIB 动态代理
public class ProxyDemoTest {
public static void main(String[] args) {
//定义一个被代理实现类
Actor a = new Actor("藏三");
//定义方法拦截器
MyInterceptor interceptor = new MyInterceptor(a);
// 代理类class文件存入本地磁盘方便我们反编译查看源码
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\gaox\\project\\apz\\demo-base\\src\\main\\java\\com\\demo\\base\\design_partten\\proxy\\code");
//通过 CGLIB 动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
//设置父类,因为 cglib 是针对指定的类生成一个子类,所以需要父类
enhancer.setSuperclass(Actor.class);
//设置回调
enhancer.setCallback(interceptor);
//生成代理对象
Actor actorProxy = (Actor)enhancer.create();
actorProxy.dance();
actorProxy.sing();
}
}
2,CGLIB 实现原理
1. 通过 CGLIB 动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
2. 设置父类,因为 cglib 是针对指定的类生成一个子类,所以需要父类
enhancer.setSuperclass(Actor.class);
3. 设置回调,就是对方法的拦截
enhancer.setCallback(interceptor);
4. 生成代理对象
enhancer.create();
5. JDK 代理和 CGLIB 代理的区别
1. 实现原理
- JDK 代理类是针对被代理类实现的接口做一个实现,针对接口而不是实现类,所以被代理类必须实现接口,使用 JAVA 的反射技术实现。
- CBLIB 代理类是针对被代理类生成的一个子类,覆盖其中的方法,使用 asm 字节码框架实现。
2. 实现过程
- JDK代理是不需要第三方库支持,只需要JDK环境就可以进行代理,使用条件:实现InvocationHandler + 使用Proxy.newProxyInstance产生代理对象 + 被代理的对象必须要实现接口。
- CGLib必须依赖于CGLib的类库,但是它需要类来实现任何接口代理的是指定的类生成一个子类,覆盖其中的方法,是一种继承;
标签:name,接口,代理,模式,class,Person,Proxy,public From: https://www.cnblogs.com/cnff/p/17009123.html针对接口编程的环境下推荐使用JDK的代理