标签:工具 create 遇到 callback 代理模式 扩展 etc 转换 creat
JAVA代理模式 之 静态代理、jdk动态代理和cglib动态代理
面膜厂家把商品委托给代理商A销售,用户从代理商处购买面膜。
2.1. 用户只关心接口功能 visit()
2.2. Subject 接口类定义了 RealSubject 和 ProxySubject 公用的接口,这样就在任何使用RealSubject的地方都可以使用Proxy
2.3. 接口Subject 真正实现着是RealSubject ,但是它不与用户直接接触,而是通过代理
2.4. ProxySubject 同样实现了Subject 接口,用户调用ProxySubject 的时候,ProxySubject 内部调用了 RealSubject ,所以,ProxySubject 是中介者,可以增强RealSubject 操作。
优点:
可以在不修改目标对象的前提下,扩展目标对象的功能
缺点:
代理对象与目标对象实现统一的接口,会产生过多的代理类
3.1 接口类:Subject
package com.proxy;
public interface Subject {
public void visit();
}
3.2 委托类:RealSubject
package com.proxy;
public class RealSubject implements Subject{
@Override
public void visit() {
System.out.println("拜访客户");
}
}
3.3 静态代理类:ProxySubject
package com.proxy;
public class ProxySubject implements Subject{
private Subject target;
public UserDaoProxy(Subject target) {
this.target = target;
}
@Override
public void visit() {
System.out.println("开启事务");//扩展了额外功能
target.visit();
System.out.println("提交事务");
}
}
3.4 测试类:TestProxy
package com.proxy;
import org.junit.Test;
public class StaticSubjectProxy {
@Test
public void testStaticProxy(){
//目标对象
Subject target = new RealSubject();
//代理对象
ProxySubject proxy = new ProxySubject(target);
proxy.visit();
}
}
输出结果:
--- 开启事务
--- 拜访客户
--- 提交事务
与静态代理的主要区别:
静态代理在编译时已经实现,编译完成后代理类是一个实际的class文件
动态代理是在运行时动态生成的,编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM 中。
特点:
动态代理不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态接口
jdk 动态代理中主要包含一个类和一个接口
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
Proxy类:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h
) throws IllegalArgumentException
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例
注释:类加载器
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器;
Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的;
Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类;
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。
4.1 接口类:Subject
package com.proxy;
public interface Subject {
public void visit();
}
4.2 委托类:RealSubject
package com.proxy;
public class RealSubject implements Subject{
@Override
public void visit() {
System.out.println("拜访客户");
}
}
4.3 jdk 动态代理工厂:ProxySubject
package com.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory{
private Object target;// 维护一个目标对象
public ProxyFactory(Object target) {
this.target = target;
}
// 为目标对象生成代理对象
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开启事务");
// 执行目标对象方法
Object returnValue = method.invoke(target, args);
System.out.println("提交事务");
return null;
}
});
}
}
3.4 测试类:TestProxy
package com.proxy;
import org.junit.Test;
public class DynamicSubjectProxy {
@Test
public void testDynamicProxy(){
//目标对象
Subject target = new RealSubject();
System.out.println(target.getClass());
//代理对象
Subject proxy = (Subject)new ProxyFactory(target).getProxyInstance();
System.out.println(proxy.getClass());
proxy.visit();
}
}
输出结果:
--- class com.proxy.RealSubject
--- class com.sun.proxy.$Proxy4
--- 开启事务
--- 拜访客户
--- 提交事务
cglib特点
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。( 使用cglib代理的对象则无需实现接口,达到代理类无侵入。)
CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。
cglib 需要引入 jar 包:
5.1 委托类:RealSubject
package com.proxy;
public class RealSubject {
public void visit() {
System.out.println("拜访客户");
}
}
5.2 cglib 动态代理工厂:ProxySubject
package com.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class ProxyFactory implements MethodInterceptor{
private Object target;// 维护一个目标对象
public ProxyFactory(Object target) {
this.target = target;
}
//为目标对象生成代理对象
public Object getProxyInstance() {
//工具类
Enhancer en = new Enhancer();
//设置父类
en.setSuperclass(target.getClass());
//设置回调函数
en.setCallback(this);
//创建子类对象代理
return en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("开启事务");
// 执行目标对象的方法
Object returnValue = method.invoke(target, args);
System.out.println("关闭事务");
return null;
}
}
5.3 测试类:TestProxy
package com.proxy;
import org.junit.Test;
public class DynamicSubjectProxy {
@Test
public void testDynamicProxy(){
//目标对象
RealSubject target = new RealSubject();
System.out.println(target.getClass());
//代理对象
Subject proxy = (Subject)new ProxyFactory(target).getProxyInstance();
System.out.println(proxy.getClass());
proxy.visit();
}
}
输出结果:
--- class com.proxy.RealSubject
--- class com.proxy.RealSubject$$EnhancerByCGLIB$$552188b6
--- 开启事务
--- 拜访客户
--- 提交事务
标签:工具 create 遇到 callback 代理模式 扩展 etc 转换 creat
原文地址:https://www.cnblogs.com/LYshuqian/p/8979704.html