首页 > 编程 > Java > 正文

谈谈Java中的代理

2019-11-08 03:14:19
字体:
来源:转载
供稿:网友

代理是java常用的设计模式,代理类通过调用被代理类的相关方法,实现对相关方法增强。比如加入事务、日志、报警发邮件等操作。

java

静态代理

静态代理,就是由程序员手动编写代理类或者用工具生成代理类的代码,再进行编译生成class文件,实现代理。比如简单工厂模式。

用法:

代理类和目标类都实现相同接口。代理类持有目标类的引用。

缺点: 静态代理要为每个目标类创建一个代理类,当需要代理的对象太多,那么代理类也变得很多。代理类违背了可重复代理只写一次的原则。

动态代理

为了解决静态代理的缺点,于是引入了动态代理。 它有一个好处,那就是不用写很多代理类,生成的代理类数量是固定的。 一般动态代理分为2种:

JDK动态代理

JDK动态代理是JDK自带的,不依赖第三方框架。 它的实现原理,就是利用Java的反射机制,创建一个实现接口的代理类。

用法:

被代理对象必须实现接口。代理对象由代理工厂自动生成。

下面贴个例子

接口类:

public interface Subject { public void doSomething(); }

实现类:

public class RealSubject implements Subject { public void doSomething() { System.out.PRintln("do 了 some thing ..."); } }

代理工厂:

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyHandler implements InvocationHandler { private Object target; //绑定委托对象,并返回代理类 public Object bind(Object target) { this.target = target; //绑定该类实现的所有接口,取得代理类 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy , Method method , Object[] args)throws Throwable { Object result = null; //这里就可以进行所谓的AOP编程了 //在调用具体函数方法前,执行功能处理 result = method.invoke(target, args); //在调用具体函数方法后,执行功能处理 return result; }}

测试类:

public class TestProxy { public static void main(String args[]) { ProxyHandler proxy = new ProxyHandler(); //绑定该类实现的所有接口 Subject sub = (Subject) proxy.bind(new RealSubject()); sub.doSomething(); }}

CGLIB代理

使用CGLIB代理需要引入CGLIB库,它使用字节码技术实现代理。

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 CGLibProxy implements MethodInterceptor { private Object targetObject;// CGLib需要代理的目标对象 public Object createProxyObject(Object obj) { this.targetObject = obj; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(obj.getClass()); enhancer.setCallback(this); Object proxyObj = enhancer.create(); return proxyObj;// 返回代理对象 } public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object obj = null; if ("addUser".equals(method.getName())) {// 过滤方法 checkPopedom();// 检查权限 } obj = method.invoke(targetObject, args); return obj; } private void checkPopedom() { System.out.println("检查权限 checkPopedom()!"); } }public class Test { public static void main(String[] args) { Subject sub = (Subject) new CGLibProxy().createProxyObject(new RealSubject()); sub.doSomething();}

2种动态代理的区别

JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。 而CGLIB动态代理是利用asm开源包,加载代理对象类的class文件,修改其字节码生成子类来处理。

在 Spring 中, * 如果目标对象实现了接口,默认情况下会采用JDK动态代理实现AOP * 如果目标对象实现了接口,可以强制使用CGLIB实现AOP * 如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换

如何强制使用CGLIB实现AOP?

添加CGLIB依赖在Spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>如果是SpringBoot,在配置文件设置spring.aop.proxy-target-class=true

JDK动态代理和CGLIB字节码生成的区别?

JDK动态代理只能对实现了接口的类生成代理,而不能针对未实现接口的类CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法因为是继承,所以该类或方法最好不要声明成final
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表