一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情。
概念:委托一个代理类对另一个类进行控制(代理类中有被代理类的对象,同时可以在代理类中增强)
使用场景:aop(可以控制被代理类是否被调用,是否被代理)。
优点:
- 确保被代理类的隐秘性
- 降低耦合性(不用挨个加需要增强的方法)
缺点:
- 类数量的增多,结构更复杂。
1.代码实现
1.静态代理
静态代理就是把增强的方法写在代理的类中,在编译时就确定了,这样耦合性比较高,除了方法量级较小或者增强的方法固定,其他情况不推荐。
subject接口
public interface PlayLol{
public void plya();
}
realSubject
public class IsPlay implements PlayLol{
public void play() {
System.out.println("开始玩");
}
}
proxy
public class ProxySubject implements PlayLol{
private PlayLol playLol;
//关键,将被代理对象传进来
public ProxySubject(final PlayLol playLol) {
this.playLol = playLol;
}
public void play() {
System.out.println("打开电脑");
//可以增加控制 ,可以不让他玩。。。
subject.play();
System.out.println("15投");
}
}
调用
public class MainClass {
public static void main(String[] args) {
PlayLol playLol = new IsPlay();
playLol.paly();
System.out.println("============");
ProxySubject proxySubject = new ProxySubject(playLol);
proxySubject.paly();
}
}
2.动态代理:
1.JDK代理
代理类
public class ProxyHandler implements InvocationHandler {
private Object object;
public DynamicProxyHandler(final Object object) {
this.object = object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("先开电脑");
Object result = method.invoke(object, args);
System.out.println("关电脑");
return result;
}
}
调用
public class MainClass {
public static void main(String[] args) {
PlayLol subject = new IsPlay();
/**
* ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
* Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
* InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法
* 都是固定写法
*/
PlayLol proxySubject = (PlayLol) Proxy.newProxyInstance(PlayLol.class.getClassLoader(),
new Class[]{PlayLol.class},
new ProxyHandler(subject));
proxySubject.play();
}
2.CGLib动态代理
如果被代理类没有接口不可以使用jdk动态代理
被代理类
public class IsPlay{
public void play() {
System.out.println("开始玩");
}
}
代理类
public class CglibProxy implements MethodInterceptor {
private Object target;//业务类对象,供代理方法中进行真正的业务方法调用
//相当于JDK动态代理中的绑定
public Object getInstance(Object target) {
this.target = target; //给业务对象赋值
Enhancer enhancer = new Enhancer(); //创建加强器,用来创建动态代理类
enhancer.setSuperclass(this.target.getClass()); //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
// 以上都是固定写反
}
// 实现回调方法
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("开电脑");
proxy.invokeSuper(obj, args); //调用业务类(父类中)的方法
System.out.println("关电脑");
return null;
}
}
调用
public class MainClass {
public static void main(String[] args) {
IsPlay play= new IsPlay();
CglibProxy cglibProxy = new CglibProxy();
IsPlay realSubjectProxy =
(IsPlay) cglibProxy.getInstance(play);
realSubjectProxy.play();
}
}
引用:CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。