设计模式--代理模式

简介:

代理模式的定义: 为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
       当一个复杂对象的多份副本须存在时,代理模式可以结合享元模式以减少存储器用量。典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象。而作用在代理者的运算会转送到原本对象。一旦所有的代理者都不存在时,复杂对象会被移除。

组成:

  • 抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
  • 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
  • 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用也叫被代理角色。

分类:

  • 静态代理
  • 由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的.class 文件就已经存在了
  • 静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)
  • 与代理对象一起实现相同的接口或者继承相同的父类
    优点:
    - 在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展
    缺点:
    - 因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类
    - 一旦接口增加方法,目标对象与代理对象都要维
  • 动态代理
  1. JDK动态代理

• 代理对象不需要实现接口,但是被代理对象需要实现接口,否则不能用动态代理
• Java语言自带功能,无需加载第三类实现,只需要你实现invocationHandler接口,重写invoke方法即可
• 通过拦截器加反射的方式实现
• 实现和调用起来比较简单
• 只能代理继承接口的类
• jdk自带的代理使用上有个限制,只能为接口创建代理类

  1. cglib代理

• 第三方提供的工具,基于字节码处理框架ASM1实现的,性能比较高 • 无需通过接口来实现,通过实现子类的方式来完成调用
• 针对类来实现代理
• 对指定目标类产生一个子类,通过方法拦截技术拦截所有的父类方法的调用
• 静态代理与JDK动态代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理–cglib代理
• cglib代理也叫做子类代理,它是在内存中构建一个子对象从而实现对目标对象功能扩展
• 在AOP编程中,选择代理模式
(1). 目标对象需要实现接口,用JDK代理
(2). 目标对象不需要实现接口,用cglib代理 •
• 在内存中动态构建子类,代理的类不能为final,否则报错java.lang.IllegalArgumentException
• 目标对象的方法如果是final/static,那么就不会被拦截,既不会执行目标对象额外的业务方法

使用场景:

       动态代理的常见使用场景有 RPC 框架的封装、AOP(面向切面编程)的实现、JDBC 的连接等。
       Spring 框架中同时使用了两种动态代理 JDK Proxy 和 CGLib,当 Bean 实现了接口时,Spring 就会使用 JDK Proxy,在没有实现接口时就会使用 CGLib,我们也可以在配置中指定强制使用 CGLib,只需要在 Spring 配置中添加 <aop:aspectj-autoproxy proxy-target-class=“true”/> 即可。
       JDK Proxy 是 Java 语言内置的动态代理,必须要通过实现接口的方式来代理相关的类,而 CGLib 是第三方提供的基于 ASM 的高效动态代理类,它通过实现被代理类的子类来实现动态代理的功能,因此被代理的类不能使用 final 修饰。

案例说明:

静态代理:
public interface IService {
    void test();
}
public class ServiceImpl implements IService {
    @Override
    public void test() {
        System.out.println("我是ServiceImpl中的test方法!");
    }
}
public class StaticProxy implements IService {
	
	private IService target;

	public StaticProxy(Iservice target) {
		this.target = target;
	}
	
	 @Override
    public void test() {
        System.out.println("我是StaticProxy中的test方法,begin------!");
        target.test();
        System.out.println("我是StaticProxy中的test方法,end ------!");
    }
}
public class ProxyTest {
    
    public static void main(String[] args) {
    	// 创建目标对象
    	Iservice service = new ServiceImpl();
    	// 创建代理对象
        StaticProxy proxy = new StaticProxy(service);
        //通过代理对象来执行操作
        proxy.test();
    }
}
JDK代理:
public interface IService {
    void test();
}
public class ServiceImpl implements IService {
    @Override
    public void test() {
        System.out.println("我是ServiceImpl中的test方法!");
    }
}
public class JDKProxy implements IService {
	
	private Object target;

	public JDKProxy(Object target) {
		this.target = target;
	}
	
	public Object getProxyInstance() {
		return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("JDK 代理开始。。。");
                        // 反射机制调用目标对象的方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("JDK 代理结束。。。");
                        return returnValue;
                    }
               }) ;
	}
} 
public class Test {
    public static void main(String[] args) {
        IService service = new ServiceImpl();
        JDKProxy proxy = new JDKProxy(service);
        IService instanceObject = (IService)proxy.getProxyInstance();
        instanceObject.test();
    }
}
CGLib代理:
		// 引入需要依赖的包
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>3.3.0</version>
		</dependency>
public class User {
	public void say(){
		System.out.println("我是普通对象");
	}
}
public class CGLibProxy implements MethodInterceptor {

	private Object target;

	public CGLibProxy(Object target) {
		this.target = target;
	}
	
	/**
     * 给目标对象创建一个代理对象
     * @return
     */
	public Object getProxyInstance() {
		// 1. 创建一个工具类
        Enhancer enhancer = new Enhancer();
        // 2. 设置父类
        enhancer.setSuperclass(target.getClass());
        // 3. 设置会带哦函数
        enhancer.setCallback(this);
        // 4. 创建子类对象,即代理对象
        return enhancer.create();
	}
	
	/**
     * 实现对被代理对象的方法调用
     * @param o
     * @param method
     * @param objects
     * @param methodProxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cgLib代理模式开始。。。");
        Object returnValue = method.invoke(target, objects);
        System.out.println("cgLib代理结束");
        return returnValue;
    }
}
public class Test {

    public static void main(String[] args) {
        CGLibProxy proxy = new CGLibProxy(new User());
        User user = (User)proxy.getProxyInstance();
       	user.say();
    }
}

综上所述,就是动态代理的简单示例,比如现在有一个场景,就是对所有的接口进行统计调用次数,或者对所有的请求添加请求日志,我们可以在代理类里面,增加一些前置或者后置操作。


  1. ASM 是一个 Java 字节码操控框架。它能够以二进制形式修改已有类或者动态生成类。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类.
    不过ASM在创建class字节码的过程中,操纵的级别是底层JVM的汇编指令级别,这要求ASM使用者要对class组织结构和JVM汇编指令有一定的了解 ↩︎

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值