基础代码准备
接口类:
public interface IUser {
/**
* 判断用户的权限
* @param uid 用户的UID
* @return
*/
public boolean isAuthUser(int uid);
}
实现类:
/**
* 类的实现
* @author Jason
*
*/
public class UserImpl implements IUser {
@Override
public boolean isAuthUser(int uid) {
//做一些权限验证的工作
System.out.println(uid);
//....
return false;
}
}
静态代理
由程序员创建或特定工具自动生成源代码,再对其编译,在程序运行前,代理类的.class文件就已经存在了。
原理:
对普通一个接口与一直实现类在加入一个代理类,用于包装实现类中实现的方法,而业务使用方只需要实例化代理类,并传递需要代理的普通类即可。
优点:
编译时生成代码,性能高
缺点:
一个代理类只能为一个接口服务,开发中必然会产生过多的代理
所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码
代码示例
代理类
/**
* 通过代理类,实现代理接口,通过构造进行实现的代理,在每个方法里面进行日志捕获
* <pre>
* 外部实现权限验证的时候,只需要之所想该方法即可,不需要再去实现UserImpl方法了
* <pre>
*/
public class UserProxy implements IUser {
private UserImpl userImpl;
// 构造的时候直接传入代理实现类
public UserProxy(UserImpl userImpl) {
super();
this.setUserImpl(userImpl);
}
@Override
public boolean isAuthUser(int uid) {
System.out.println("proxy insert msg:准备权限验证,有必要这里可以发送消息到MQ,做实时登录验证次数预警处理");
boolean b = userImpl.isAuthUser(uid);
System.out.println("proxy insert msg:验证完成,做一些清理等工作.....");
return b;
}
// ***********get,set************
public UserImpl getUserImpl() {
return userImpl;
}
public void setUserImpl(UserImpl userImpl) {
this.userImpl = userImpl;
}
}
public static void main(String[] args) {
UserProxy userProxy = new UserProxy(new UserImpl());
userProxy.isAuthUser(5);
}
动态代理
原理:
动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。
优点
可以通过一个代理类,完成所有代理工作,不需要向静态代理需要一个一个实现接口来代理
缺点
通过反射动态代理方法将消耗系统性能,如果非常多的话,性能比较低
JDK动态代理
原理:JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理
代理类:UserJDKProxy
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK动态代理代理类,可以将InvocationHandler接口的子类想象成一个代理的最终操作类
* JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这个也是缺陷
* @author Jason
*
*/
public class UserJDKProxy implements InvocationHandler {
// 需要代理的类
private Object target;
public UserJDKProxy() {
super();
}
/**
* 绑定委托对象并返回一个代理类 ClassLoader loader:类加载器 Class<?>[] interfaces:得到全部的接口 InvocationHandler
* h:得到InvocationHandler接口的子类实例
*
* @param target
* @return
*/
public Object initUserJDKProxy(Object target) {
this.target = target;
// 可以看出这里的第二个参数是获取接口,那么也就是说我们实现代理,需要类去实现接口,在有的时候,类是没有接口的,所以这里是一个缺陷
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
/**
* 调用具体的方法
*
* @param proxy
* 指被代理的对象
* @param method
* 要调用的方法
* @param args
* 方法调用时所需要的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy:这里拦截处理一下事情....,如监控参数、插入日志....");
//传入处理对象和参数
Object object = method.invoke(target, args);
System.out.println("proxy:这里做一些收尾工作....");
return object;
}
}
测试:
UserJDKProxy userJDKProxy=new UserJDKProxy();
IUser iUser=(IUser) userJDKProxy.initUserJDKProxy(new UserImpl());
iUser.isAuthUser(19);
CGLib动态代理
原理:cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
这里需要注意,改包需要引入外部包,提供pom
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
代理类:UserCglibProxy
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 采用CGLib方式动态代理类
* @author Jason
*
*/
public class UserCglibProxy implements MethodInterceptor {
private Object target;
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
//回调方法
enhancer.setCallback(this);
//创建代理对象
return enhancer.create();
}
// 回调方法
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("可以做一些监控、预警等工作...");
Object object = proxy.invokeSuper(obj, args);
System.out.println("收尾工作....");
return object;
}
}
测试
UserCglibProxy userCglibProxy=new UserCglibProxy();
UserImpl userImpl=(UserImpl) userCglibProxy.getInstance(new UserImpl());
userImpl.isAuthUser(50);
其他
动态代理在我们使用的框架Spring中已经运用到,主要是AOP,他主要是动态代理+反射的方式
如Spring通过CGLib来实现了类代理方式,通过Java动态代理来实现接口代理,从而把两种动态代理结合使用
来源:oschina
链接:https://my.oschina.net/u/103310/blog/635321