反射的应用:动态代理
-
动态代理,在编译时候不指明代理类,而在运行时确定。
-
静态代理:代理类和被代理类都是在编译期间就确定下来,这样不利于程序的拓展,同时每一个地阿里类只能为一个接口服务,这样一来程序开发必然会产生过多的代理,最好可以通过一个代理类完成全部的代理功能。
-
动态代理和静态代理相比的优点:抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样我们就可以更加灵活和统一的处理众多方法。
-
静态代理举例:
package com.ntt.sts;
import jdk.nashorn.internal.runtime.regexp.JoniRegExp;
interface ClothFactory {
void produceCloth();
}
//代理类
class ProxyClothFactory implements ClothFactory {
private ClothFactory factory;
public ProxyClothFactory(ClothFactory factory){
this.factory = factory;
}
@Override
public void produceCloth() {
System.out.println("做一些生产前准备工作");
factory.produceCloth();
System.out.println("做一些生产后收尾工作");
}
}
class NickFactory implements ClothFactory{
@Override
public void produceCloth() {
System.out.println("nick工厂开始制作衣服");
}
}
class Test{
public static void main(String[] args) {
NickFactory nickFactory = new NickFactory();
ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nickFactory);
proxyClothFactory.produceCloth();
}
}
- 可以看出在代理类中创建了接口的属性,
- 动态代理
interface Human{
String getBelief();
void eat(String food);
}
//被代理的类
class SuperMan implements Human{
@Override
public String getBelief() {
return "I believe i can fly!";
}
@Override
public void eat(String food) {
System.out.println("Superman eat " + food);
}
}
/**
* 要想实现动态代理,需要解决的问题?
* 问题一:如何根据加载到内存中的被代理类,动态的创建一个地阿里类及其对象。
* 问题二:当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同命方法。
*/
class ProxyFactory{
//调用此方法,返回一个代理类的对象
public static Object getProxyInstance(Object obj){
//根据对象不同动态的创建一个代理类对象
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
myInvocationHandler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),myInvocationHandler);
}
}
class MyInvocationHandler implements InvocationHandler{
private Object obj;//需要使用被代理类对象进行赋值
public void bind(Object obj){
this.obj = obj;
}
//当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()
//将被代理类要执行的方法a的功能就声明在invoke()方法中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//method即为代理类对象调用的方法,此方法也就作为了被代理类对象调用的方法
//obj :被代理类的对象
Object invoke = method.invoke(obj, args);
//上述方法的返回值就作为当前类中invoke()的返回值
return invoke;
}
}
class ProxyTest{
public static void main(String[] args) {
SuperMan superMan = new SuperMan();
//proxyInstance就是代理类的对象
Human proxyInstance =(Human) ProxyFactory.getProxyInstance(superMan);
//当通过代理类对象调用方法时,会自动的调用被代理类中的同名方法。
proxyInstance.eat("四川麻辣烫");
String belief = proxyInstance.getBelief();
System.out.println(belief);
}
}
- Proxy代理模式是一种结构型设计模式,主要解决的问题是:在直接访问对象时带来的问题
代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
就好像艺人开演唱会需要经纪人进行事前准备、事后收拾残局的,为被代理对象(明星)只需要在演唱会开始的时候进行演唱。
- 为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。
更通俗的说,代理解决的问题当两个类需要通信时,引入第三方代理类,将两个类的关系解耦,让我们只了解代理类即可,而且代理的出现还可以让我们完成与另一个类之间的关系的统一管理,但是切记,代理类和委托类要实现相同的接口,因为代理真正调用的还是委托类的方法。
- 由于静态代理的方法在编译的时候就固定下来,如果艺人向做别的事情(加一个方法),则所有的从接口、代理类、被代理类全部都要加一个方法。
- 动态代理通过反射动态的获取被代理类的方法以及其实现的接口,进行动态的生成代理对象。通过该代理对象就可以调用代理类的方法了。