前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >动态代理的介绍(非aop) 基于接口 基于子类 举例说明

动态代理的介绍(非aop) 基于接口 基于子类 举例说明

原创
作者头像
韦恩少爷的背
修改2020-03-23 10:33:12
5090
修改2020-03-23 10:33:12
举报
文章被收录于专栏:SSM框架学习SSM框架学习

动态代理方式

代码语言:javascript
复制
动态代理:
特点:字节码随用随创建,随用随加载
作用:不修改源码的基础上对方法增强
分类:
    基于接口的动态代理
    基于子类的动态代理

一、基于接口的动态代理

代码语言:javascript
复制
    基于接口的动态代理:
       涉及的类:Proxy
       提供者:JDK官方
    如何创建代理对象:
       使用Proxy类中的newProxyInstance方法
    创建代理对象的要求:
        被代理类最少实现一个接口,如果没有则不能使用
    newProxyInstance方法的参数:
         ClassLoader:类加载器
               它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。
               固定写法:
                   代理是谁就写谁的 XXX.getClass().getClassLoader()
 
         Class[]:字节码数组
               它是用于让代理对象和被代理对象有相同的方法
               固定写法:
                   代理谁就写谁的 XXX.getClass().getInterfaces()
 
         InvocationHandler:
               他是让我们写如何代理。一般是写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的
               此接口的实现类都是谁用谁写。
 
               注意:如果我们的类不实现任何接口的时候,执行Client会报代理异常
                       不使用任何接口,proxy这种代理无法使用

举例:卖东西 前提:有一个接口IProducer,一个实现类Producer(最后我会附上这部分的代码(“动态代理介绍”) IProducer proxyProducer为动态代理对象,方法执行调用它

代码语言:javascript
复制
newProxyInstance方法
	被代理类最少实现一个接口,如果没有则不能使用
	前两步都是一个套路
		1.Class 加载代理对象
			代理XXX就写XXX.getClass().getClassLoader()
		2.Class[]
			让代理对象和被代理对象有相同的方法
			代理XXX就写XXX.getClass().getClassInterfaces()
		下一步不同了
		3.InvocationHandler 调用处理程序
			有下面的方法
				这里是Object类型,所以我们创建代理对象的时候记得强转一下
		            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {}
						 * @param proxy     代理对象的引用
			             * @param method    当前执行的方法
			             * @param args   当前执行方法所需要的参数
			             * @return 和被代理对象方法有相同的返回值
			             	执行方法的一般写法
			             		Object returnValue = null;
			             		returnValue=执行方法;
			             		return returnValue;

再正常执行方法

代码语言:javascript
复制
public class Client {
    public static void main(String[] args) {
        //匿名类访问外部成员变量的时候,要求是最终的final
        //弹幕:局部变量随着方法的调用而调用,随着方法消失而消失,而对内存的内容不会立即消失,还会继续引用局部变量
        final Producer producer = new Producer();
//返回的是Object类型 需要强转一下
		IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
		        producer.getClass().getInterfaces(),
		        new InvocationHandler() {
		            /**匿名内部类
		             *
		             * 作用:执行被代理对象的任何接口方法都会经过该方法
		             * 方法参数的含义
		             * @param proxy     代理对象的引用
		             * @param method    当前执行的方法
		             * @param args   当前执行方法所需要的参数
		             * @return 和被代理对象方法有相同的返回值
		             * @throws Throwable
		             */
		            @Override
		            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		                Object returnValue = null;
		                //1.获取方法执行的参数
		                Float money = (Float) args[0];
		                //2.判断当前方法是不是销售
		                if ("saleProduct".equals(method.getName())) {
		                	//执行操作
		                    returnValue = method.invoke(producer, money * 0.8f);
		                }
		                return returnValue;
		            }
		        });
		proxyProducer.saleProduct(1000f);

二、基于子类的动态代理

代码语言:javascript
复制
基于子类的动态代理:
    涉及的类:Enhancer
    提供者:第三方cglib库
如何创建代理对象:
    使用Enhancer类中的create方法
创建代理对象的要求:
    被代理类不能是最终类
create方法的参数:
    Class:字节码
        它是用于指定被代理对象的字节码。
        XXX.getClass().getClassLoader();

    Callback:用于提供增强的代码(和
        它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
        此接口的实现类都是谁用谁写。
        我们一般写的都是该接口的子接口实现类:MethodInterceptor 方法拦截

举例:卖东西 前提:有一个接口IProducer,一个实现类Producer(最后我会附上这部分的代码(“动态代理介绍”) Producer cglibProducer为动态代理对象,方法执行调用它

代码语言:javascript
复制
被代理类不能是最终类(不能是final)
	create方法
			1.Class加载代理对象
				代理XXX就写XXX.getClass().getClassLoader()
			2.Callback:用于提供增强的代码
				一般写的都是该接口的子接口实现类
				public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {}
					 * 执行被代理对象的任何方法都会经过该方法
		             * @param proxy
		             * @param method
		             * @param args
		             *      以上三个参数和基于接口的动态代理中invoke方法的参数是一样的
		             * @param methodProxy:当前执行方法的代理对象(一般用不上8
				             	执行方法的一般写法
				             		Object returnValue = null;
				             		returnValue=执行方法;
				             		return returnValue;

再正常执行方法

代码语言:javascript
复制
  public class Client {
    public static void main(String[] args) {
        //匿名类访问外部成员变量的时候,要求是最终的final
        final Producer producer = new Producer();
  Producer cglibProducer=(Producer)Enhancer.create(producer.getClass(), new MethodInterceptor() {
            /**
             * 执行被代理对象的任何方法都会经过该方法
             * @param proxy
             * @param method
             * @param args
             *      以上三个参数和基于接口的动态代理中invoke方法的参数是一样的
             * @param methodProxy:当前执行方法的代理对象
             * @return
             * @throws Throwable
             */
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                Object returnValue = null;
                //1.获取方法执行的参数
                Float money = (Float) args[0];
                //2.判断当前方法是不是销售
                if ("saleProduct".equals(method.getName())) {
                    returnValue = method.invoke(producer, money * 0.8f);
                }
                return returnValue;
            }
        });
        cglibProducer.saleProduct(1000f);

三、源码及模块结构

在这里插入图片描述
在这里插入图片描述

IProducer接口

代码语言:javascript
复制
public interface IProducer {
    /**
     * 销售
     * @param money
     */
    public void saleProduct(float money);
}

Producer类

代码语言:javascript
复制
/**
 * 一个生产者
 */
public class Producer implements IProducer {
    /**
     * 销售
     * @param money
     */
    public void saleProduct(float money){
        System.out.println("销售产品,并拿到钱:"+money);
    }
}

Proxy里的Client(执行方法测试

代码语言:javascript
复制
public class Client {
    public static void main(String[] args) {
        final Producer producer = new Producer();
        //返回的是Object类型 需要强转一下
        IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
                producer.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object returnValue = null;
                        //1.获取方法执行的参数
                        Float money = (Float) args[0];
                        //2.判断当前方法是不是销售
                        if ("saleProduct".equals(method.getName())) {
                            //执行操作
                            returnValue = method.invoke(producer, money * 0.8f);
                        }
                        return returnValue;
                    }
                });
        proxyProducer.saleProduct(1000f);
    }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 动态代理方式
    • 一、基于接口的动态代理
      • 二、基于子类的动态代理
        • 三、源码及模块结构
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档