关于“静态代理”与“动态代理”

关于“静态代理”与“动态代理”


一、什么是代理?

概念:

  代理就是一个中间桥梁,生活中类似于中介。比如商家就是一个中介,顾客从商家那购买商品,商家从厂家那进购商品,商家充当的是顾客跟厂家之间的桥梁;又或者说,房屋中介也是一个代理,房屋中介替房主寻找租客,租客从中介那租到房子,房屋中介就是租客跟房主之间的桥梁。
  开发过程中,A类要调用C类中的方法,但是却被禁止调用,这时就需要引进一个B类来充当代理,A类访问B类,B类访问C类,即A类通过B类去调用C类中的方法。

作用:

1、 功能增强:在原有的功能上增加新的功能。比如房屋中介在租房子的时候会收取相应的中介费,这个中介费就是房主所没有收取的,即在原先的功能之上,额外增加一些条件,或者说功能。
2、 控制访问:代理会控制你去访问目标类。比如商家不会让顾客直接去厂家那购买,或者厂家不提供顾客的个人购买。

实现方式:

1、静态代理
2、动态代理

二、静态代理

1、什么是静态代理?

  代理类是手工创建的Java文件,同时代理的目标对象是固定的。(所谓静态就是在程序执行之前,其中的代理关系是确定好了的)

2、优缺点?

  优点:代码清晰明了,符合思维逻辑,所以容易理解,使用起来比较方便

  缺点:当目标类比较多的时候, 会产生大量的代理类。(为避免这个缺点,使用动态代理)

3、学习案例

首先创建一个接口类,如下:

public interface ToySell{
	//在这个接口中定义一个方法
	float sell(int amount);
}

创建一个厂家类(目标类),实现该接口(重写接口中的方法)

public class ToyFactory_A implements ToySell {
    @Override
    public float sell(int amount) {
        //假设一个玩具的价格是25元
        return 25.0f;
    }
}

创建一个商家类(代理类),实现该接口(重写接口中的方法)

public class ToyShop_A implements ToySell{
	//首先声明商家所代理的厂家具体是谁
	private ToyFactory_A factory_a = new ToyFactory_A();
	@Override
	//实现销售玩具的功能
	public float sell(int amount) {
	    //向厂家发送订单
	    float price = factory_a.sell(amount);
	    price = price+20;//商家需要代理费..增强功能,代理类在完成目标类方法调用后,增强了功能
	    //在目标类的方法调用之后,做其他的功能都是增强的意思
	    System.out.println("买一送一");
	
	    return price;
	}
}

创建一个主函数,在主函数中声明商家,并通过商家去调用厂家中的方法,实现购买玩具。

public class shopMain {
    public static void main(String[] args) {
        //厂家代理的商家对象
        ToyShop_A toyShop_a = new ToyShop_A();
        float price = toyShop_a.sell(1);
        System.out.println("通过A商家购买的玩具的单价是:"+price);
    }
}

测试结果:

三、动态代理

1、什么是动态代理?

  在程序执行过程中,使用jdk的反射机制,创建代理类对象,并且动态地指定目标类,而不需要创建类文件。

2、动态代理的实现

jdk动态代理:使用Java反射包中的类和接口实现动态代理

cglib动态代理:属于第三方工具库,创建代理对象。其原理是继承,cglib通过继承目标类,创建子类,在子类中重写父类中的方法来实现功能的修改。(只要目标类能继承即可,即目标类不能是final的)

3、jdk动态代理

(1)关于反射机制(关于Method的使用)

创建一个接口service

public interface Helloservice{
	public void sayHello(String name);
}

创建一个实现类,并实现该接口

public class HelloServiceIml implements HelloService{	
	@Override
	public void sayHello(String name) {
	    System.out.println("你好,"+name);
	}
}

创建一个测试类

public class TestApp{
	public static void main(String[] args) {
    	//创建一个service对象
    	HelloService service = new HelloServiceImpl();
    	//直接通过对象来调用方法执行
    	service.sayHello("张三");
    }
}

上面的测试类使用反射机制来执行

public class TestApp {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //使用 反射 机制执行sayHello方法。核心 Method(类中的方法)
        HelloService target1 = new HelloServiceImpl();
        //获取sayHello名称对应的method类对象
        //.class获取类,.getMethod获取类中的方法
        Method method = HelloService.class.getMethod("sayHello", String.class);//这个时候这个method就能代表sayHello方法了
        //通过method可以执行sayHello方法调用
        //表达的意思是:执行target1对象的sayHello,参数是张三
        Object obj = method.invoke(target1,"张三");
	/**
         * invoke是Method类中的一个方法,表示执行方法的调用
         * 参数:
         *  1、Object,表示对象的,要执行这个对象的方法
         *  2、Object...args,方法执行时的参数值
         *  返回值:
         *          object:方法执行后的返回值
         */
    }
}

测试结果:

(2) jdk动态代理的实现

 在反射包中有三个类,InvocationHandler、Method、Proxy

 ★InvocationHandler接口

 1)Invoke()方法:表示代理对象要执行的功能代码。

  代理类要完成的功能:目标方法的执行,功能的增强。

代码原型
 public Object invoke(Object proxy, Method method, Object[] args)

 2)三个参数:
   Object proxy:jdk创建的代理对象
   Method method:目标类中的方法。
   Object[] args:目标类中方法的参数

 3)如何使用?
   1、创建InvocationHandler接口的实现类
   2、重写Invoke()方法,将所要实现的功能写在这里

 ★Method类(目标类中的方法)
   作用:通过method执行某个目标类中的方法,如method.invoke();
      method.invoke(目标对象,方法的参数)
   比如:
      //表达的意思是:执行target1对象的sayHello,参数是张三
      Object obj = method.invoke(target1,“张三”);

 ★Proxy类(代替new的使用来创建代理对象)
 1)方法:静态方法newProxyInstance()

方法原型:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

 2)三个参数:
   ClassLoader loader:类加载器,负责向内存中加载对象。通过使用反射机制来获取对应的ClassLoader类a,a.getClass().getClassLoader(),从而获取目标对象的类加载器
   Class<?>[] interfaces:目标对象的接口,由反射获取。
   InvocationHandler h:代理类要实现的功能,自己写的。

 3)返回值:代理对象

(2) 动态代理的实现步骤

 1)创建接口,定义目标类要完成的功能
 2)创建目标类实现接口
 3)创建InvocationHandler接口的实现类,在其invoke()方法中实现代理类的功能(调用目标方法+增强功能)
 4) 使用Proxy类的静态方法,创建代理对象,并把返回值转为接口类型。

(3)学习案例

首先定义一个接口

public interface ToySell{
  //在这个接口中定义一个方法
  float sell(int amount);
}

创建接口的目标类

//目标类
public class ToyFactory_A implements ToySell{
  @Override
  public float sell(int amount) {
  	System.out.println("目标类方法");
        return 50.0f;
  }
}

创建接口的实现类,完成功能的实现与增强

public  class MySellHandler implements InvocationHandler{
    private Object service = null;
   //动态代理:目标对象不是固定的,所以需要传入进来
   //传入谁,就给谁创建代理
   public MySellHandler(Object service) {
	 this.service = service;//给目标对象赋值
   }
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       //声明返回值
       Object resp = null;
      //执行目标方法
       resp = method.invoke(service,args);
 
       //功能增强
       if(resp!=null){
           float price = (float)resp;
           price = price+10;
           resp = price;
       }
       System.out.println("买一送一");
       return resp;//返回价格
   }
}

创建主函数

public class MainShop {
    public static void main(String[] args) {
        //使用proxy创建代理对象

        //第一步,创建目标对象
        ToySell toyFactory_a = new ToyFactory_A();
        //第二步,创建InvocationHandler对象
        InvocationHandler handler = new MySellHandler(toyFactory_a);

        //第三步,创建代理对象,注意将返回值转成接口
        ToySell proxy = (ToySell) Proxy.newProxyInstance(toyFactory_a.getClass().getClassLoader(),
                toyFactory_a.getClass().getInterfaces(),
                handler);
        //第四步,通过代理执行方法
        float price = proxy.sell(1);
        System.out.println("动态代理调用方法的结果是:"+price);
    }
}

测试结果

总结

  小白一枚,知识来源视频学习所汇集。可以去看视频更详细学习。学习视频链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值