动态代理和AOP

之前说过了我对IOC的理解,这篇文章说以下我对动态代理和基本的对AOP的理解。

所谓动态代理就是,在运行时,动态创建实现了一组指定接口的实现类对象。

比如有:

interface A {
}
interface B{
}

即:

Object o = 方法(new Class[] {A.class,B.class}) ,

o实现了A和B两个接口

但是我们在运行时是无法写源代码来进行这个类的创建。

这时候我们需要用到Proxy类下的newProxyInstance()方法。

1.newProxyInstance()方法

Object proxyObject = Proxy.newProxyInstance(ClassLoader classLoader, Class[] interfaces, InvocationHandler h);

1. 方法作用:动态创建实现了interfaces数组中所有指定接口的实现类对象!

参数;

1. ClassLoader:类加载器!

* 它是用来加载器的,把.class文件加载到内存,形成Class对象!

2. Class[] interfaces:指定要实现的接口们

3. InvocationHandler:代理对象的所有方法(个别不执行,getClass())都会调用InvocationHandler的invoke()方法。

我们来看这个方法的使用方式:

public class Demo1 {
    @Test
    public void fun1() {
        /* 1. ClassLoader
         * 方法需要动态生成一个类,这个类实现了A、B接口,然后创建这个类的对象!
         * 需要生成一个类,这个类也需要加载到方法区中,谁来加载,当然是ClassLoader!!!
         * 2. Class[] interfaces
         * 它是要实现的接口们
         * 3. InvocationHandler
         * 它是调用处理器
         * 代理对象的实现的所有接口中的方法,内容都是调用InvocationHandler的invoke()方法。
         */
        ClassLoader loader = this.getClass().getClassLoader();//把当前使用的这个类的类加载器给代理对象使用
        InvocationHandler h = new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                System.out.println("动态代理!");
                return "xxx";
            }
        };
        // 使用三大参数创建代理对象!!!
        Object o = Proxy.newProxyInstance(loader, new Class[]{A.class, B.class}, h);
        // 强转成A和B类型
        A a = (A) o;
        B b = (B) o;

        Object result = a.aaa("hello", 100);
        System.out.println(result);
    }
}

和两个接口:

interface A {
    public void a();
    public void aa();
    public Object aaa(String s, int i);
}

interface B {
    public void b();
    public void bb();
}

将o强转成A和B类型后,可以调用A接口中的方法和B接口中的方法,但是不论调用什么方法最中都是调用的InvocationHandler中的 invoke方法即打印输出动态代理!但是除此之外所有的Object中的非本地方法都是输出这个结果,这是因为Native方法不是用Java编写的所有就不需要管这个部分。

2.InvocationHandler接口其中只有invoke一种方法:

public Object invoke(Object proxy, Method method, Object[] args);

这个invoke()方法在调用代理对象所实现接口中的方法时被创建

* Object proxy:当前对象,即代理对象!在调用谁的方法!

* Method method:当前被调用的方法(目标方法)

* Object[] args:实参!

当在调用这个方法时,其对应关系为:

3.用动态代理进行增强

假设一个接口Waiter以及其一个实现类,该实现类提供一个方法:

public interface Waiter {
    // 服务
    public void serve();
}
public class ManWaiter implements Waiter {
    public void serve() {
        System.out.println("服务中...");
    }
}

为了在调用ManWaiter的serve方法之外添加其他能力,就需要用动态代理来实现这样的功能:

public class Demo2 {
    @Test
    public void fun1() {
        Waiter manWaiter = new ManWaiter();//目标对象
        /*
         * 给出三个参数,来创建方法,得到代理对象
         */
        ClassLoader loader = this.getClass().getClassLoader();
        Class[] interfaces = {Waiter.class};
        InvocationHandler h = new WaiterInvocationHandler(manWaiter);//参数manWaiter表示目标对象
        // 得到代理对象,代理对象就是在目标对象的基础上进行了增强的对象!
        Waiter waiterProxy = (Waiter)Proxy.newProxyInstance(loader, interfaces, h);

        waiterProxy.serve();//前面添加“您好”, 后面添加“再见”
    }
}

class WaiterInvocationHandler implements InvocationHandler {
    private Waiter waiter;//目标对象

    public WaiterInvocationHandler(Waiter waiter) {
        this.waiter = waiter;
    }
}

public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("您好!");
        this.waiter.serve();//调用目标对象的目标方法
        System.out.println("再见!");
        return null;
    }
}

我们在invoke 中实现了对对象能力的增强,这就是使用动态代理的能力。

4.在之前的基础上,为了提升动态代理的能力,实现了让目标对象和增强都是可以切换的,在创建目标对象之外,还需要查创建增强对象接口,

public interface BeforeAdvice {
    public void before();
}

public interface AfterAdvice {
    public void after();
}

创建一个代理工厂,ProxyFactory:

/**
 * 1. 创建代理工厂
 * 2. 给工厂设置三样东西:
 *   * 目标对象:setTargetObject(xxx);
 *   * 前置增强:setBeforeAdvice(该接口的实现)
 *   * 后置增强:setAfterAdvice(该接口的实现)
 * 3. 调用createProxy()得到代理对象
 *   * 执行代理对象方法时:
 *   > 执行BeforeAdvice的before()
 *   > 目标对象的目标方法
 *   > 执行AfterAdvice的after()
 * @author cxf
 *
 */
public class ProxyFactory {
    private Object targetObject;//目标对象
    private BeforeAdvice beforeAdvice;//前置增强
    private AfterAdvice afterAdvice;//后置增强

    /**
     * 用来生成代理对象
     * @return
     */
    public Object createProxy() {
        /*
         * 1. 给出三大参数
         */
        ClassLoader loader = this.getClass().getClassLoader();
        Class[] interfaces = targetObject.getClass().getInterfaces();
        InvocationHandler h = new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                /*
                 * 在调用代理对象的方法时会执行这里的内容
                 */
                // 执行前置增强
                if(beforeAdvice != null) {
                    beforeAdvice.before();
                }

                Object result = method.invoke(targetObject, args);//执行目标对象的目标方法
                // 执行后置增强
                if(afterAdvice != null) {
                    afterAdvice.after();
                }

                // 返回目标对象的返回值
                return result;
            }
        };
        /*
         * 2. 得到代理对象
         */
        Object proxyObject = Proxy.newProxyInstance(loader, interfaces, h);
        return proxyObject;
    }
}

当我们使用代理工厂的时候就可以这样做来实现对象的增强:

public void fun1() {
        ProxyFactory factory = new ProxyFactory();//创建工厂
        factory.setTargetObject(new ManWaiter());//设置目标对象
        factory.setBeforeAdvice(new BeforeAdvice() {//设置前置增强
            public void before() {
                System.out.println("您好!");
            }
        });

        factory.setAfterAdvice(new AfterAdvice() {//设置后置增强
            public void after() {
                System.out.println("再见!");
            }
        });

        Waiter waiter = (Waiter)factory.createProxy();
        waiter.shouQian();
    }

动态代理类似于装饰者模式,但是比装饰者模式更加灵活,动态代理的作用就是最终实现AOP(面向切面编程)。面向切面编程中,切面是一种新的模块机制,用来描述分散在对象,类或者方法中的横切关注点,横切关注点是会影响到整个应用程序关注功能,于正常的业务是正交的,这些横切关注点可以是事务,日志和安全性等其他功能。

原文地址:https://www.cnblogs.com/winterfells/p/8616737.html

时间: 2025-01-01 10:34:37

动态代理和AOP的相关文章

动态代理和AOP切面编程

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /* * 动态代理和AOP切面编程 */ //定义一个接口 interface Person { void eat(); void breath(); } // 定义一个实现接口的实现类,即为被代理类 class Student implements Person { @Overr

黑马程序员--Java高新(10)_动态代理和AOP编程

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 一, 动态的核心 动态代理的两个核心,Proxy 和 InvocationHandler,都是Java.lang.reflect包下的接口类;由此也可以看出动态代理是反射的高级应用! 代理与反射的关系如何体现?从代理的建立过程的构建方法及其参数可见一斑: 1,代理最核心的Handler的唯一方法invoke()的核心参数Method method,是一个Class类型,并且在代理调用时,inv

关于反射和动态代理和AOP

package Exercise.reflect; /** * 反射把java中所有的东西都当做对象,甚至是类的本身也作为一种对象,并把它作为Class的对象的实例: * 反射是把类.类的属性.方法都作为一个对象类进行剖析: * * 为什么需要反射?把类变成活的,当一个类经过java虚拟机编译之后会生成对应的字节码文件,即xxx.class, * 而反射就是去解析这个类的信息,包括其中所包含的变量和方法: * 在运行期间去加载一个类,并对类进行剖析,甚至可以给一个类的属性动态的赋值,也可以去唤醒

【Spring】AOP之JDK动态代理和CGLib动态代理

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 一.JAVA动态代理  1.1 代理模式         代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创

Spring中AOP的两种代理方式(Java动态代理和CGLIB代理)

第一种代理即Java的动态代理方式上一篇已经分析,在这里不再介绍,现在我们先来了解下GCLIB代理是什么?它又是怎样实现的?和Java动态代理有什么区别? cglib(Code Generation Library)是一个强大的,高性能,高质量的Code生成类库.它可以在运行期扩展Java类与实现Java接口. cglib封装了asm,可以在运行期动态生成新的class. cglib用于AOP,jdk中的proxy必须基于接口,cglib却没有这个限制. 原理区别: java动态代理是利用反射机

spring aop原理 JDK动态代理和CGLIB动态代理

Spring的两大特性是IOC和AOPIOC负责将对象动态的注入到容器,从而达到一种需要谁就注入谁,什么时候需要就什么时候注入的效果.理解spring的ioc也很重要.但是今天主要来和大家讲讲aop.AOP 广泛应用于处理一些具有横切性质的系统级服务,AOP 的出现是对 OOP 的良好补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理.日志.缓存等等. AOP实现的关键在于AOP框架自动创建的AOP代理.AOP代理主要分为静态代理和动态代理, 静态代理的代表为AspectJ:动态代理则

JDK动态代理和CGLIB动态代理

转载自http://www.itzhai.com/java-dong-tai-dai-li-zhi-jdk-dong-tai-dai-li-he-cglib-dong-tai-dai-li-mian-xiang-qie-mian-bian-cheng-aop-yuan-li.html 静态代理 静态代理相对来说比较简单,无非就是聚合+多态: 参考:设计模式笔记 – Proxy 代理模式 (Design Pattern) 动态代理 我们知道,通过使用代理,可以在被代理的类的方法的前后添加一些处理方

JDK动态代理和CGLIB动态代理+源码下载

在上一篇文章-java代理详解讲解实现机制,一种是继承另外一种是组合,而且通过做实现也证明使用组合的方式更加的灵活.之后提到了代理的两种种类,一种是静态代理,另外一种是动态代理.上一篇文件中着重介绍的是静态代理(相对于动态代理很容易理解).这一片文章就接着介绍动态代理. 动态代理实现的最终效果:通过以一个统一的方式实现对任意的接口/类的代理.相比较静态代理而言,我们可以不用再无限制的增加代理类,不用再写许多重复的代码.很符合面向对象设计原则中的"开闭原则":对修改关闭,对扩展开放. 动

JDK动态代理和CGLIB的区别

Aspect默认情况下不用实现接口,但对于目标对象,在默认情况下必须实现接口 如果没有实现接口必须引入CGLIB库 我们可以通过Advice中添加一个JoinPoint参数,这个值会由spring自动传入,从JoinPoint中可以取得 参数值.方法名等等 1.如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2.如果目标对象实现了接口,可以强制使用CGLIB实现AOP 3.如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换