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

动态代理方式

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

一、基于接口的动态代理

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

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

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;

再正常执行方法

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);

二、基于子类的动态代理

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

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

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

被代理类不能是最终类(不能是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;

再正常执行方法

  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);

三、源码及模块结构

动态代理的介绍(非aop) 基于接口 基于子类 举例说明_第1张图片
IProducer接口

public interface IProducer {
    /**
     * 销售
     * @param money
     */
    public void saleProduct(float money);
}

Producer类

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

Proxy里的Client(执行方法测试

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);
    }
}

你可能感兴趣的:(Spring部分,SSM学习,aop,proxy,spring,java)