Java-代理模式

代理模式:
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
开闭原则,增加功能:
代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要修改已经封装好的委托类。
1、静态代理(Static Proxy)
是由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行之前,代理类.class文件就已经被创建了。

第一步:创建服务类接口
public interface BuyHouse {  
    void buyHouse();  
}  

第二步:实现服务接口
public class BuyHouseImpl implements BuyHouse {  
    @Override  
    public void buyHouse() {  
        System.out.println("我要买房");  
    }  
}

第三步:创建代理类
 public class BuyHouseProxy implements BuyHouse {  
    private BuyHouse buyHouse;  
    public BuyHouseProxy(final BuyHouse buyHouse) {  
        this.buyHouse = buyHouse;  
    }  
    @Override  
    public void buyHouse() {  
        System.out.println("买房前准备");  
        buyHouse.buyHouse();  
        System.out.println("买房后装修");  
    }  
}

第四步:编写测试类
public class HouseApp {  
    public static void main(String[] args) {  
        BuyHouse buyHouse = new BuyHouseImpl();  
        BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse);  
        buyHouseProxy.buyHouse();  
    }  
}

2、JDK动态代理(Dynamic Proxy)
动态代理是在程序运行时通过反射机制动态创建的。

说明:实际上就是在内存中生产一个对象,该对象实现了指定的目标对象的所有接口,代理对象和目标对象是兄弟关系。
jdk自带动态代理技术,需要使用一个静态方法来创建代理对象,它需要目标对象必须实现接口,生产的代理对象和原对
象都实现相同的接口。
参数解释:Proxy.newProxyInstance(...)
1.ClassLoader loader:
固定写法,指定目标类对象的类的加载器即可,用于加载目标类及其接口的字节码文件,通常使用目标类的字节码文件调
用getClassLoader()方法可得到。
2.Class<?>[] interfaces:
固定写法,指定目标类的所以接口的字节码对象的数组,通常使用目标类的字节码文件调用getinterfaces()方法可得到
3.InvocationHander h:
这个参数是一个接口,主要关注它里面的一个方法,它会在代理类调用方法时执行,也就是说,在代理类对象中调用的任何方法都会执行invoke()方法。所以在此方法中进行代码的扩展
	invoke()方法中参数的含义:
		1.proxy:就是代理类对象的一个引用也就是Proxy.newProxyInstance()方法的返回值;此引用几乎不会用到。
		2.method:对应的就是触发invoke执行的方法的Method对象。假如我们调用了Xxx方法,该方法触发了invoke执
				  行,那么method就是Xxx方法对应的反射对象Method3.args:代理对象调用方法时传入的实际参数
示例:
1、创建接口
public interface OrderInterface {
    public String order(String foodName);
    public void test1();
    public void test2();
}
2、目标对象实现接口
public class Customer implements OrderInterface {
    public String order(String foodName){
        return "已下单点了"+foodName;
    }
    @Override
    public void test1() {}
    @Override
    public void test2() {}
}
3、测试类,进行代理对象创建
public class Test {
    public static void main(String[] args) {
        //1. 准备一个目标类对象,也就是顾客对象
        Customer customer = new Customer();
        //2. 使用jdk的API动态的生成代理对象
        OrderInterface deliveryClerk = (OrderInterface) Proxy.newProxyInstance(customer.getClass().getClassLoader(),
                customer.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if ("order".equals(method.getName())) {
                            Object result = method.invoke(customer, args);
                            System.out.println("已经接订单在送去的路上");
                            return result + "买了一杯珍珠奶茶";
                        } else {
                            return method.invoke(customer, args);
                            //使用method反射调用,在原对象中执行方法,并不改变逻辑,也就是说原封不动调用原来的逻辑
                        }
                    }
                }
                );
        //3. 调用代理对象执行相应的方法
        String result=deliveryClerk.order("鱼香肉丝盖饭");
        System.out.println(result);
    }
}

3、基于cglib父类的动态代理
第三方cglib动态代理技术也是可以使用一个动态代理方法来创建代理对象,它不要求目标类实现接口,但是要求目标类不能是最终类,也就是说不能被final修饰。因为cglib是基于目标类生成该类的一个子类作为代理类,所以目标对象必须可以被继承。基于父类的动态代理是在内存中生成一个对象,该对象继承了原对象,所以代理对象实际上就是原对象的子类。

maven依赖:
<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib-nodep</artifactId>
	<version>3.3.0</version>
</dependency>
参数解释:
1.Class type:
指定我们要代理的目标类的字节码对象,也就是指定目标类的类型。
1.callback:
也是一个接口,只是名称定义的作用。只是让别的接口去继承它,提供一个方法它会在合适的时候回来调用它。通常使用其子类
它的子类MethodInterceptor(方法拦截器)接口,其只有一个方法,叫做intercept()方法
	intercept()方法中的参数:
		1.proxy:就是代理类对象的一个引用也就是Enharcer.create()方法的返回值;此引用几乎不会用到。
		2.method:对应的就是触发intercept执行的方法的Method对象。假如我们调用了Xxx方法,该方法触发了invoke执行,
				  那么method就是Xxx方法对应的反射对象Method3.args:代理对象调用方法时传入的实际参数
		4.methodProxy:方法的代理对象,一般不做处理,暂时忽略。
示例:
1、创建目标类
public class Customer {
    public String order(String foodName){
        return "已下单点了"+foodName;
    }
    public void test1() {
    }
    public void test2() {
    }
}
2、创建代理测试类
public class Test {
    public static void main(String[] args) {
        // 创建一个目标类对象,也就是顾客对象
        Customer customer = new Customer();
        // 使用CGLIB创建代理对象
        Customer deliveryClerk = (Customer) Enhancer.create(customer.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                // 判断,如果是order方法,则增强
              if ("order".equals(method.getName())) {
                            Object result = method.invoke(customer, args);
                            System.out.println("已经接订单在送去的路上");
                            return result + "买了一杯珍珠奶茶";
                        } else {
                            return method.invoke(customer, args);
                            //使用method反射调用,在原对象中执行方法,并不改变逻辑,也就是说原封不动调用原来的逻辑
                        }
                    }
                }
                );
        //3. 调用代理对象执行相应的方法
        String result=deliveryClerk.order("鱼香肉丝盖饭");
        System.out.println(result);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值