AOP基础—代理模式

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

按照代理的创建时期,代理类可以分为两种。

静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
动态代理:在程序运行时,运用反射机制动态创建而成。

静态代理的每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。

动态代理 
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。

Spring AOP使用动态代理技术在运行期间织入增强的代码,主要有两种代理机制:基于JDK的动态代理;基于CGLib的动态代理。JDK本身只提供接口的代理,而不支持类的代理。

一.JDK动态代理

JDK动态代理主要涉及java.lang.reflect包下的两个类:Proxy类和InvocationHandler接口。
InvocationHandler接口:

public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
} 

参数说明: 
Object proxy:指被代理的对象。 
Method method:要调用的方法 
Object[] args:方法调用时所需要的参数

InvocationHandler接口的子类可以看成代理的最终操作类。

Proxy类: 
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException 

参数说明: 
ClassLoader loader:类加载器 
Class<?>[] interfaces:得到全部的接口 
InvocationHandler h:得到InvocationHandler接口的子类实例

JDK动态代理主要涉及java.lang.reflect包下的两个类:Proxy和InvocationHandler。其中,InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。

代码:移除性能监视横切代码

public class ForumServiceImpl implements ForumService{
   public void removeTopic(int topicId){
       //①在此位置原有的横切代码被移除(抽取切面中)
       System.out.println("模拟删除Topic记录:"+topicId);
       try{
           Thread.currentThread().sleep(20);
       }catch(Exception e){
           throw new RuntimeException(e);
       }
       //①在此位置原有的横切代码被移除(抽取切面中)
   }
   public void removeForum(int forumId){
       //②在此位置原有的横切代码被移除(抽取切面中)
       System.out.println("模拟删除Forum记录:"+forumId);
       try{
           Thread.currentThread().sleep(40);
       }catch(Exception e){
           throw new RuntimeException(e);
       }
       //②在此位置原有的横切代码被移除(抽取切面中)
   }
}

把抽取出来的代码性能监视代码放置到PerformanceHandler中:

public class PerformanceHandler implements InvocationHandler{
   private Object target;       //target为目标业务类
   public PerformanceHandler(Object target){
       this.target=target;
   }
   public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
       PerformanceMonitor.begin(target.getClass().getName()+"."+method.getName());    //③
       Object obj=method.invoke(target, args);  //⑤通过反射调用业务类的目标方法
       PerformanceMonitor.end();     //④
       return obj;
   }
}

invoke()方法中③④处的代码为性能监视的横切代码,只出现一次。⑤处的method.invoke()语句通过java反射机制间接调用目标对象的方法,这样InvocationHandler的invoke()方法就将横切逻辑代码和业务类方法的业务逻辑代码编织到一起,我们可以把InvocationHandler看成一个编织器。

我们通过Proxy和PerformanceHandler创建ForumService接口的代理实例:

import java.lang.reflect.Proxy;

public class TestForumService {
    public static void main(String[] args){
        ForumService target=new ForumServiceImpl();   //被代理对象
        PerformanceHandler handler=new PerformanceHandler(target);  //将目标业务类和横切代码编织到一起
        ForumService proxy=(ForumService)Proxy.newProxyInstance(   //创建代理实例
                target.getClass().getClassLoader,
                target.getClass().getInstances(),
                handler);
        proxy.removeForum(10);
        proxy.removeTopic(1012);
    }
} 

但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。

二.CGLib动态代理

CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有的父类方法的调用,并顺势织入横切逻辑。

下面采用CGLib技术写一个可以为任何类创建织入性能监视横切逻辑代理对象的代理创建器:

import class CglibProxy implements MethodInterceptor{
    private Enhancer enhancer = new Enhancer();
    public Object getProxy(Class clazz){
        enhancer.setSuperclass(clazz);   //设置需要创建子类的类
        enhancer.setCallback(this);
        return enhancer.create();     //通过字节码技术动态创建子类实例
    }
    public Object intercept(Object obj,Method method,Object[] args,MethodProxy proxy) throws Throwable{//拦截父类所有方法的调用
         PerformanceMonitor.begin(obj.getClass().getName()+"."+method.getName());  //①
         Object result = proxy.invokeSuper(obj,args);   //通过代理类调用父类中的方法
         PerformanceMonitor.end();     //②
         return result;
    }
} 

getProxy(Class clazz):为一个类创建动态代理对象,该代理对象通过扩展clazz创建代理对象。在这个代理对象中,我们织入性能监视的横切逻辑①②。

intercept(Object obj,Method method,Object[] args,MethodProxy proxy):是CGLib定义的Intercept接口的方法,它拦截所有目标类方法的调用,obj:目标类的实例;method:目标类方法的反射对象;args:方法的动态入参;proxy:代理类实例。

下面通过CglibProxy为ForumServiceImpl类创建代理对象,并测试代理对象的方法:

import java.lang.reflect.Proxy;
public class TestForumService{
     public static void main(String[] args){
            CglibProxy proxy = new CglibProxy();
            ForumServiceImpl forumService = (ForumServiceImpl)proxy.getProxy(ForumServiceImpl.class);   //动态生成子类的方式创建代理类
            forumService.removeForum(10);
            forumService.removeTopic(1023);
    }
}
时间: 2024-10-14 11:56:33

AOP基础—代理模式的相关文章

AOP之代理模式(一)

AOP,为Aspect OrientedProgramming的缩写,意为:面向切面,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率. 说了一堆很官方的话,大家可能不是特别明白,不过这些算是我们实践的理论寄出去,还是很有必要知道的,但是现在不必要很懂,接下来从最简单的代码开始,一步步的慢慢深入了解,到底什么是AOP,什么是代理模式.学习,就是这样一个理论与

反射实现AOP动态代理模式(Spring AOP实现原理)

其实AOP的意思就是面向切面编程. OO注重的是我们解决问题的方法(封装成Method),而AOP注重的是许多解决问题的方法中的共同点,是对OO思想的一种补充! 还是拿人家经常举的一个例子讲解一下吧: 比如说,我们现在要开发的一个应用里面有很多的业务方法,但是,我们现在要对这个方法的执行做全面监控,或部分监控.也许我们就会在要一些方法前去加上一条日志记录. 我们写个例子看看我们最简单的解决方案 我们先写一个接口IHello.java代码如下: package sinosoft.dj.aop.st

AOP之代理模式(三)

JDK自从1.3版本开始,就引入了动态代理,JDK的动态代理用起来非常简单,但是它有一个限制,就是使用动态代理的对象必须实现一个或多个接口 .如果想代理没有实现接口的类可以使用CGLIB包.先来看看GCLIB的具体使用,然后再对应代码深入理解. 在使用CGLIB时需引入cglib-nodep-2.1_3.jar包. 先来一个基础类,注意,这里没有对应的接口. public class GreetingImpl { public void sayHello(String name) { Syste

AOP之代理模式(二)

上篇博文介绍的静态代理有一个最主要的缺点:每个业务类,必须有一个代理类.这样在程序中就会出现很多个代理类,这样的代码还是有坏味道的.这篇文章就为了解决这个问题而来--JDK动态代理. 先来看一看最基本的业务接口和业务类: <span style="font-size:18px;">/** * 业务接口类 * @author sunliduan * */ public interface Greeting { void sayHello(String name); }<

代理模式——用AOP测试业务层方法的执行时间

代理模式 对代理模式的理解,通过http://www.runoob.com/design-pattern/proxy-pattern.html 对AOP的代理模式,参考https://www.cnblogs.com/xujiming/p/5737531.html 目标:测试service层每一个方法的执行时间: 代理模式的本质:将被代理对象注入给代理对象,当调用代理对象时,实际上,是在调用被注入的被代理对象 理解: 代理对象 被代理对象 代理类 被代理对象 商家 厂商 房屋中介 房东 静态代理:

开涛spring3(6.1) - AOP 之 6.1 AOP基础

6.1.1  AOP是什么 考虑这样一个问题:需要对系统中的某些业务做日志记录,比如支付系统中的支付业务需要记录支付相关日志,对于支付系统可能相当复杂,比如可能有自己的支付系统,也可能引入第三方支付平台,面对这样的支付系统该如何解决呢? 传统解决方: 1)日志部分提前公共类LogUtils,定义“longPayBegin”方法用于记录支付开始日志,“logPayEnd”用于记录支付结果: 2)支付部分,定义IPayService接口并定义支付方法“pay”,并定义了两个实现:“PointPayS

Java的代理模式

最近在学习Spring,关于Spring AOP的代理模式不是很了解,看了一篇博文就懂了. https://www.cnblogs.com/cenyu/p/6289209.html Java的三种代理模式 1.代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方

JAVA基础(一)——代理模式

实现java代理一般分为静态代理和动态代理(jdk代理和cglib代理) 代理模式 简单的说就是对原有的业务进行代理,外界通过代理访问真实对象,代理类似现在的中介机构,房产中介就是一个代理,代理房东,租户只要找到代理而无须关心房东是谁,代理能在房东的基础上增强房东的行为. 代理模式代码 JAVA静态代理 业务接口 package com.rrg.proxy.jdk.staticProxy; /** * * @author abc * */ public interface Count { /**

代理模式与AOP

代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务.简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途.在后面我会解释这种间接