Java设计模式-代理模式

为其他对象提供一种代理以控制对这个对象的访问。
代理模式和适配器模式很像,适配器模式把A接口转换成B接口

public class BAdapter implements B{

	private A a;
	
	public Badapter(A a) {
		this.a = a;
	}
	
	public void b() {
		a.toString();
	}
}

而代理模式不是把A接口转换成B接口,而是把A接口转换成A接口:

public class AProxy implements A{

	private A a;
	
	public Badapter(A a) {
		this.a = a;
	}
	
	public void b() {
		a.toString();
	}
}

那这代理模式有啥用,不和直接调用A一样的嘛?
但是可以在调用的方法前后加上一些逻辑判断,或者权限校验,甚至日志记录,那作用不就体现出来了吗。

public void b() {
	if (getAuth()) {
		this.a.a();
	} else {
		throw new BussinessException("");
	}
}

静态代理

为每一个类去写一个代理类,这样太繁琐了,所以有了动态代理

动态代理

JDK动态代理

jdk动态代理只可以对接口进行代理,原因在后面解释:

定义接口

public interface Service {

	public void doSave();
}

实现类

public class HelloService implements Service{

	@Override
	public void doSave() {
		System.out.println("执行保存方法");
	}

}

jdk动态代理要实现java.lang.reflect.InvocationHandler接口:

public class JdkProxy implements InvocationHandler {

	private Service target;

	public JdkProxy(Service target) {
		this.target = target;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		long start = System.currentTimeMillis();
		System.out.println("调用方法" + method.getName() + "开始");
		Object o = method.invoke(target, args);
		System.out.println("调用方法:" + method.getName() + ",参数:" + args + " 耗时 :"
				+ (System.currentTimeMillis() - start) + "ms");

		return o;
	}

}

测试

public class Test {
 
	public static void main(String[] args) {
		Service s = new HelloService();
		JdkProxy p = new JdkProxy(s);
		Service s2 = (Service)Proxy.newProxyInstance(Service.class.getClassLoader(), new Class<?>[]{Service.class}, p);
		s2.doSave();
	}
}

为什么说jdk动态代理只能代理接口呢?
查看源码Proxy.newProxyInstance(ClassLoader arg, Class<?>[] arg0, InvocationHandler arg1)方法

    //JDK 创建动态代理 
    public static Object newProxyInstance(ClassLoader loader, 
                                          Class<?>[] interfaces, 
                                          InvocationHandler h) 
        throws IllegalArgumentException 
    { 
        ...... 
        // 重点 
        final Class<?>[] intfs = interfaces.clone(); 
        ...... 
        // 生成增强之后的动态代理 Class 
        Class<?> cl = getProxyClass0(loader, intfs); 
        // 创建增强之后的动态代理 Class 实例对象 
        try { 
            ...... 
            final Constructor<?> cons = cl.getConstructor(constructorParams); 
            ...... 
            return cons.newInstance(new Object[]{h}); 
        } catch (IllegalAccessException|InstantiationException e) { 
            ...... 
        } 
    } 

进入 Class<?> cl = getProxyClass0(loader, intfs); 方法

    private static final WeakCache<ClassLoader, Class<?>[], Class<?>> 
            proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); 
     
    private static Class<?> getProxyClass0(ClassLoader loader, 
                                           Class<?>... interfaces) { 
        if (interfaces.length > 65535) { 
            throw new IllegalArgumentException("interface limit exceeded"); 
        } 
     
        // proxyClassCache 是 Proxy 的静态变量,是 WeakCache 类, 
        // 本质调用的 ProxyClassFactory 的 apply 方法 
        return proxyClassCache.get(loader, interfaces); 
    } 
    private static final class ProxyClassFactory 
        implements BiFunction<ClassLoader, Class<?>[], Class<?>> 
    { 
        // 所有代理类的前缀 
        private static final String proxyClassNamePrefix = "$Proxy"; 
     
        // 一个用来生成唯一类名的数字 
        private static final AtomicLong nextUniqueNumber = new AtomicLong(); 
     
        // 重点,这个方法被上面的 proxyClassCache.get 调用,也就是被 WeakCache 的 get 调用 
        @Override 
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { 
     
            ...... // 一堆对接口的校验逻辑,省略 
     
            String proxyPkg = null;     // 代理类包名 
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL; // flag 
            ...... 
            long num = nextUniqueNumber.getAndIncrement();  // 唯一类名 
            // 拼接的唯一全限定代理类名 
            String proxyName = proxyPkg + proxyClassNamePrefix + num; 
            
            //重点!!!这里生成了增强的代理类字节码文件
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass( 
                proxyName, interfaces, accessFlags); 
                
            try { 
            // 调用 native 方法加载代理类字节码到内存 
                return defineClass0(loader, proxyName, 
                                    proxyClassFile, 0, proxyClassFile.length); 
            } catch (ClassFormatError e) { 
                ...... 
            } 
        } 
    } 

java自动生成了一个 P r o x y 0 代 理 类 , 已 经 继 承 于 Proxy0代理类,已经继承于 Proxy0Proxy0了,那就没办法继承其它类了

CGLIB动态代理

是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。
我们要实现MethodInterceptor接口,调用Enhancer类进行配置,生成最后的代理对象

public class CglibProxy<T> implements MethodInterceptor {
	
	private T target;

	public CglibProxy(T target) {
		this.target = target;
	}
	// 创建代理对象
	public Object getProxyInstance() {

		// 1.cglib工具类
		Enhancer en = new Enhancer();
		// 2.设置父类
		en.setSuperclass(this.target.getClass());
		// 3.设置回调函数
		en.setCallback(this);

		return en.create();
	}

	@Override
	public Object intercept(Object arg0, Method arg1, Object[] arg2,
			MethodProxy arg3) throws Throwable {
		long start = System.currentTimeMillis();
		
		System.out.println("调用方法" + arg1.getName() + "开始");
		Object result = arg1.invoke(target, arg2);
		System.out.println("调用方法:" + arg1.getName() + ",参数:" + arg2 + " 耗时 :"
				+ (System.currentTimeMillis() - start) + "ms");
	
		return result;
	}

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值