面试篇之HR问什么是动态代理?什么是动静代理?
退出交换群返回:CN.ITLTT.COM
何为代理?
Java中的代理,开源了解为通过代理去拜访理论的指标对象,比方呢?咱们平时交易二手车的中间商,就能够看作一个代理类,不过你也能够间接去和二手车的客人交易。
那这种状况,在Java中就被称之为代理,代理类除了去实现目标对象外,他还能够去在其中减少许多额定性能。
实践扩大:
次要解决的问题:在间接拜访对象时带来的问题,比如说:要拜访的对象在近程的机器上。在面向对象零碎中,有些对象因为某些起因(比方对象创立开销很大,或者某些操作须要安全控制,或者须要过程外的拜访),间接拜访会给使用者或者系统结构带来很多麻烦,咱们能够在拜访此对象时加上一个对此对象的拜访层。
代理模式的必要条件:独特接口、代理对象、指标对象。
宏观个性:对客户端只暴露出接口,不裸露它以下的架构。
长处:两头隔离了一层,更加合乎开闭准则。
代理是一种?
代理是一种设计模式
- 他并非一种自带的性能,而是一种设计模式。
- 在代理模式中,一个类代表另一个类的性能。
- 这种类型的设计模式属于结构型模式。
- 在代理模式中,咱们创立具备现有对象的对象,以便向外界提供性能接口。
- 目标:为其余对象提供一种代理以管制对这个对象的拜访。
代理模式分类
代理模式分为两种类型:
- 动态代理
- 动静代理
实现动态代理
实践不多说,从代码中了解。
创立接口
首先,咱们创立一个接口,个别咱们一个性能都会去设计一个接口,包含咱们的三层架构也是这样,所以我这也写一个接口。
/** * @author JanYork * @date 2022/10/25 8:59 * @description 假如Demo是买货色的接口 */public interface Demo { /** * 买货色 * @param name 货色的名字 * @param price 货色的价格 * @return 买货色的后果 */ String buy(String name, int price);}
那咱们就,假如这个Demo
是买货色的接口。
也是提供一个简简单单的购买货色的办法(实际上就是输入测试一下)。
实现接口
咱们还要去实现这个接口,也就是咱们的接口实现类。
/** * @author JanYork * @date 2022/10/25 9:03 * @description 实在的Demo类(被代理类) */public class RealDemo implements Demo { public RealDemo(String name, int price) { this.name = name; this.price = price; } private String name; private int price; @Override public String buy(String name, int price) { System.out.println("买了" + name + "花了" + price + "元"); return "买了" + name + "花了" + price + "元"; }}
给他两个参数,一个结构,而后重写接口提供的办法,这个不须要多说。
代理类
/** * @author JanYork * @date 2022/10/25 9:05 * @description Demo的代理类 */public class ProxyDemo implements Demo { private RealDemo realDemo; public ProxyDemo(String name, int price) { this.realDemo = new RealDemo(name, price); } @Override public String buy(String name, int price) { System.out.println("-----代理类开始买货色------"); String result = realDemo.buy(name, price); System.out.println("------代理类买货色完结------"); return result; }}
创立代理后咱们也须要去实现这个Demo
接口。
而后须要注入实现接口的类的对象(也就是实在类)。
private RealDemo realDemo;
而后实现结构:
public ProxyDemo(String name, int price) { this.realDemo = new RealDemo(name, price);}
而后在重写办法外面调用,能够在调用办法前后干一些事件。
而后咱们创立一个Test
类测试:
动态代理缺点
问:既然动态代理能够不便的达到目标,那他有什么毛病吗?
动态代理在代码运行之前就须要创立好代理类,因而对于每一个代理对象都须要建一个代理类去代理。如果说,你须要代理的对象很多,那就须要创立很多代理类,升高程序的可维护性。
问:那如何解决这个缺点呢?
动静构建代理类,也就是动静代理。
动静代理
动静代理的代理类是在运行过程中产生的。
Java
提供了两种实现动静代理的形式:
- 基于
JDK
的动静代理。 - 基于
Cglib
的动静代理。
特点:字节码随用随创立,随用随加载。
作用:在不批改源码的根底上对办法加强。
基于JDK实现
实现Jdk
的动静代理须要实现InvocationHandler
接口,而后实现其中的invoke
办法。
咱们创立一个类,实现InvocationHandler
(来自java.lang.reflect
反射包下)接口。
这个类下,有十分丰盛的具体的解释,能够看看。
实现了接口后,咱们给他用Object
来代替原先动态代理类中的这一段:
private RealDemo realDemo; public ProxyDemo(String name, int price) { this.realDemo = new RealDemo(name, price);}
也就是这样:
private Object target;public ProxyHandler(Object target) { this.target = target;}
而后重写invoke
办法:
@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("-----动静代理开始------"); Object invoke = method.invoke(target, args); System.out.println("------动静代理完结------"); return invoke;}
外面有多个参数,稍后阐明。
调用
首先还是创立实在对象,并且给出结构。
RealDemo realDemo = new RealDemo("苹果", 10);
而后创立动静代理对象,将正式对象传输过来。
ProxyHandler proxyHandler = new ProxyHandler(realDemo);
而后咱们调用,实际上就是应用Proxy
这个类来调用newProxyInstance
这个办法。
Proxy.newProxyInstance(realDemo.getClass().getClassLoader(), realDemo.getClass().getInterfaces(), proxyHandler);
这个办法是一个静态方法,参数如下。
newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
第一个是一个类加载器,第二个是一个带泛型的Class数组,并且要求是一个interfaces
,第三个参数就是实现了InvocationHandler
的对象了。
那咱们调用时给出的参数就是:
//获取实在类的类加载器realDemo.getClass().getClassLoader(), //获取实在类所实现的接口realDemo.getClass().getInterfaces(),//实现InvocationHandler接口的对象proxyHandler
这部分对反射这方面常识有很多设计,不懂的还是倡议去折腾折腾。
那咱们整个调用动静对象的办法,如下:
public class TestDemo { public static void main(String[] args) {// ProxyDemo proxyDemo = new ProxyDemo("苹果", 10);// proxyDemo.buy("苹果", 10); //调用动静代理 RealDemo realDemo = new RealDemo("苹果", 10); ProxyHandler proxyHandler = new ProxyHandler(realDemo); Demo demo = (Demo) Proxy.newProxyInstance(realDemo.getClass().getClassLoader(), realDemo.getClass().getInterfaces(), proxyHandler); demo.buy("苹果", 10); }}
Proxy.newProxyInstance
办法返回的是一个Object
,咱们将他转型为咱们的接口对象。
而后通过对象调用对应办法。
成果
劣势
一个动静代理能够对N个须要代理的对象起作用,只须要将须要代理类的参数放入Proxy.newProxyInstance
办法即可。
缺点
JDK
只能代理接口!
JDK
动静代理的确只能代理接口,JDK动静代理是基于接口的形式,换句话来说就是代理类和指标类都实现同一个接口。如果想要代理类的话能够应用CGLib
,CGLib
动静代理是代理类去继承指标类,而后实现目标类的办法。
基于CGLib实现
首先引入依赖:
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>版本号</version></dependency>
如果你是Spring
我的项目,那就不用了,曾经整合了。
咱们创立一个类,用于给CGLib
测试。
/** * @author JanYork * @date 2022/10/25 10:32 * @description 基于Cglib的动静代理的指标类 */public class CgDemo { public String buy(String name, int price) { System.out.println("买了" + name + ",价格是" + price); return "买了" + name + ",价格是" + price; }}
而后创立CGLib
的代理类:
/** * @author JanYork * @date 2022/10/25 10:34 * @description */public class CgProxy implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("-----cglib代理开始------"); Object invoke = methodProxy.invokeSuper(o, objects); System.out.println("------cglib代理完结------"); return invoke; }}
调用
//创立Enhancer对象Enhancer enhancer = new Enhancer();//设置父类(也就是指标类)enhancer.setSuperclass(CgDemo.class);//设置回调函数enhancer.setCallback(new CgProxy());//创立代理对象CgDemo cgDemo = (CgDemo) enhancer.create();//调用代理对象的办法cgDemo.buy("苹果", 10);
Enhancer
是cglib.proxy
下的一个生成动静子类以启用办法拦挡的类。
Enhancer
类是CGLib
中最罕用的一个类,和JDK 1.3
动静代理中引入的Proxy
类差不多(Proxy
类是Java
动静代理机制的主类,它提供了一组静态方法来为一组接口动静地生成代理类及其对象)。和
Proxy
不同的是,Enhancer
类既可能代理一般的class
,也可能代理接口。Enhancer
创立一个被代理对象的子类并且拦挡所有的办法调用(包含从Object
中继承的toString()
和hashCode()
办法)。
成果
利用场景
问:动静代理这么牛,平时工作中有应用到吗?
在平时的业务代码,简直是用不到代理的。
然而,Spring
系列框架中的AOP
,以及RPC
框架中都用到了动静代理。
如:AOP通过动静代理对指标对象进行了加强,比方咱们最罕用的前置告诉、后置告诉等。
全篇完,我是小简,下篇再见。