`

java的代理分析

阅读更多

Spring中AOP编程的本质是:无须修改源码增加系统功能。所谓的系统功能即为AOP中的A,方面,体现在代码上称为Advice(增强):即日志、审核、权限、计时等每个系统均可能要使用到的功能。在感受AOP让我们见证神奇的背后,我们可以通过以下方式不同程度地实现:

1.  JavaSE 动态代理;
    从JDK1.3开始,便加入了可协助动态生成代理类的API。在这些API中,一个主要接口是
       java.lang.reflect.InvocationHandler以及import java.lang.reflect.Proxy。在动态代理中,我们主要编写该接口的实现类型。

2.  动态字节码生成;
     针对指定的类动态生成一个子类,并且覆盖其中的方法,从而增加系统功能。其中最流行的工具是:
     CGLIB(Code Generation Library).
     缺点:无法为 final 方法或类 提供代码。

3.   Java代码生成;
     生成新的Java源码,在其中提供横切性的代码,例如EJB的代码生成策略;
     由于动态代理和动态字节码生成技术的出现,这种做法正在逐渐退出使用;

4.  使用定制的类加载器;
     自定义类加载器,在一个类被加载时自动对其进行横切入系统功能,改变new操作符的行为。
     JBoss和AspectWerkz采用这种做法。
     缺点:偏离Java标准,在某些应用服务器中可能出现问题,因为J2EE服务器需要控制整个类加载的层级体系。

5.  语言扩展;
     增加Java语言功能,使其在OOP编程基础上从语言级别上支持AOP。这一点类似于C++扩展C,引入OO概念一样。
     AspectJ就对Java进行了扩展。
     缺点:复杂,且引用新的语言。

     OOP编程中一些模式也已经解决了AOP希望解决的部分问题:
     . Decorator(装饰器模式): 类似于静态代理;
     . CORBA在处理远程调用时提供了拦截器的概念;
     . Servlet2.3规范引入的servlet拦截器会在处理Web请求的前后被调用;

     这些解决方案的主要问题是:它们将拦截器的代码与特定的API或上下文环境(例如:处理远程调用)绑在一起,不够通用。

Spring中AOP构建在动态代码和字节码生成概念基础上, 提供更优雅、更通用的解决方案。Spring中将要增加的系统功能体现为Advice接口的实现类型。根据系统功能加入目标对象的时刻又分为:

1. 前增强(before,pre):在连接点调用之前,首先调用增强;
2. 后增强(after,post):在连接点调用之后,首先调用增强;
      a. 返回后增强(after returning advice):在调用成功(没抛异常)之后;
      b. 抛出增强(throws advice):在抛出某种特定类型的异常之后;
      c. 后增强(after advice):在连接点调用后,不管是否抛异常;
3. 环绕增强(around):完全控制流程,除完成本身工作,还要负责主动调用连接点;
      不同增强授受的参数不同;例如后增强获得实际方法的返回值,但抛出增强则不能;

我们应从可用性角度出发,尽量使用功能最弱,目的最明确的增强,这样可以使程序更加清晰。

Spring中为了对系统功能加入到目标对象的方法进行进一步精细控制,提供PointCut接口。然后将系统功能结合到目标对象的工作交由配置文件完成。Advice编写是简单的,PointCut接口的实现类是现成的,配置的代码是可以参考的,但配置文件中一个名为ProxyFactoryBean的工作原理是很重要的。为了能近距离感受AOP神奇背后的普通,我们可以自行编写ProxyFactoryBean。在看具体的源码之前,对ProxyFactory所实现的接口稍做说明:

1. BeanFactoryAware: 实现该接口的Bean对象在由Spring框架实例化完后,会由Spring框架自动注入BeanFactory对象;
2. FactoryBean: 实现该接口,通过该Bean对象所配置的Bean的名称获得的不是该Bean对象,而是该Bean对象方法getObject()返回的对象;
3. InvocationHandler: 实现该接口,动态地改变所执行原方法的功能,实现在原方法前、后或前后加入增强;

package common;   
  
import java.lang.reflect.InvocationHandler;   
import java.lang.reflect.Method;   
import java.lang.reflect.Proxy;   
import java.util.ArrayList;   
import java.util.List;   
  
import org.springframework.aop.MethodBeforeAdvice;   
import org.springframework.beans.BeansException;   
import org.springframework.beans.factory.BeanFactory;   
import org.springframework.beans.factory.BeanFactoryAware;   
import org.springframework.beans.factory.FactoryBean;   
  
public class MyProxyFactoryBean implements    
    BeanFactoryAware, FactoryBean, InvocationHandler{   
    private Object target;   
    private Class[] proxyInterfaces;   
    private List interceptorNames=new ArrayList();   
    private List realInterceptorNames=null;   
    private BeanFactory factory;   
       
    @Override  
    public Object getObject() throws Exception {   
        return Proxy.newProxyInstance(   
            target.getClass().getClassLoader(),   
            proxyInterfaces,   
            this  
        );   
    }   
  
    @Override  
    public Class getObjectType() {   
        return target.getClass();   
    }   
  
    @Override  
    public boolean isSingleton() {   
        return true;   
    }   
  
    public void setTarget(Object target) {   
        this.target=target;    
    }   
       
    public void setProxyInterfaces(String proxyInterfaces) {   
        try {   
            this.proxyInterfaces=new Class[]{Class.forName(proxyInterfaces)};   
        } catch (ClassNotFoundException e) {   
            throw new RuntimeException(e);   
        }   
    }   
  
    @Override  
    public Object invoke(Object proxy,    
            Method method, Object[] args)   
            throws Throwable {   
        if(realInterceptorNames==null) {   
            realInterceptorNames=new ArrayList();   
            for(Object o: interceptorNames) {   
                realInterceptorNames.add(factory.getBean(o.toString()));   
            }   
        }   
        for(Object o: realInterceptorNames) {   
            if(o instanceof MethodBeforeAdvice)   
                ((MethodBeforeAdvice)o).before(method, args, target);   
        }   
        Object result=method.invoke(target,args);   
           
        return result;   
    }   
       
    public void setInterceptorNames(   
            List interceptorNames) {   
        this.interceptorNames=interceptorNames;   
    }   
  
    @Override  
    public void setBeanFactory(BeanFactory arg0) throws BeansException {   
        this.factory=arg0;     
    }   
}  

 

 

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

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

 
  动态代理类:在程序运行时,运用反射机制动态创建而成。

 

1、静态代理类 

A:先定义一个接口类
  java 代码
  package ttitfly.proxy;
  public interface HelloWorld {
  public void print(); // public void say();
  }
  
  B: 定义一个该接口的实现类
  java 代码
  package ttitfly.proxy;
  public class HelloWorldImpl implements HelloWorld{
  
  public void print(){
  System.out.println("HelloWorld");
  } // public void say(){ // System.out.println("Say Hello!"); // }
  }
  
  C:定义一个静态代理类
  java 代码
  package ttitfly.proxy;
  public class StaticProxy implements HelloWorld{
  
  public HelloWorld helloWorld ;
  public StaticProxy(HelloWorld helloWorld){
  this.helloWorld = helloWorld;
  }
  
  public void print(){
  System.out.println("Welcome");
  //相当于回调
  helloWorld.print();
  }
  // public void say(){ // //相当于回调 // helloWorld.say(); // }
  }
  
  D: 一个测试类:
  java 代码
  package ttitfly.proxy;
  public class TestStaticProxy {
  
  public static void main(String[] args){
  HelloWorld helloWorld = new HelloWorldImpl();
  StaticProxy staticProxy = new StaticProxy(helloWorld);
  staticProxy.print();
  // staticProxy.say();
  }
  }
  
  可以看出静态代理类有一个很不爽的缺点:当如果接口加一个方法(把上面所有的代码的注释给去掉),所有的实现类和代理类里都需要做个实现。这就增加了代码的复杂度。动态代理就可以避免这个缺点。

 

2、动态代理
  动态代理与普通的代理相比较,最大的好处是接口中声明的所有方法都被转移到一个集中的方法中处理(invoke),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
  动态代理类只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类

与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
  Proxy类提供了创建动态代理类及其实例的静态方法。
  (1)getProxyClass()静态方法负责创建动态代理类,它的完整定义如下:
  public static Class getProxyClass(ClassLoader loader, Class[] interfaces) throws IllegalArgumentException
  参数loader 指定动态代理类的类加载器,参数interfaces 指定动态代理类需要实现的所有接口。
  (2)newProxyInstance()静态方法负责创建动态代理类的实例,它的完整定义如下:
  public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler handler) throws
  IllegalArgumentException
  参数loader 指定动态代理类的类加载器,参数interfaces 指定动态代理类需要实现的所有接口,参数handler 指定与动态代理类关联的 InvocationHandler 对象。

由Proxy类的静态方法创建的动态代理类具有以下特点:
  动态代理类是public、final和非抽象类型的;
  动态代理类继承了java.lang.reflect.Proxy类;
  动态代理类的名字以“$Proxy”开头;
  动态代理类实现getProxyClass()和newProxyInstance()方法中参数interfaces指定的所有接口;
  Proxy 类的isProxyClass(Class cl)静态方法可用来判断参数指定的类是否为动态代理类。只有通过Proxy类创建的类才是动态代理类;
  动态代理类都具有一个public 类型的构造方法,该构造方法有一个InvocationHandler 类型的参数。
  由Proxy类的静态方法创建的动态代理类的实例具有以下特点:
  1. 假定变量foo 是一个动态代理类的实例,并且这个动态代理类实现了Foo 接口,那么“foo instanceof Foo”的值为true。把变量foo强制转换为Foo类型是合法的:
  (Foo) foo //合法
  2.每个动态代理类实例都和一个InvocationHandler 实例关联。Proxy 类的getInvocationHandler(Object proxy)静态方法返回与参数proxy指定的代理类实例所关联的InvocationHandler 对象。
  3.假定Foo接口有一个amethod()方法,那么当程序调用动态代理类实例foo的amethod()方法时,该方法会调用与它关联的InvocationHandler 对象的invoke()方法。
  InvocationHandler 接口为方法调用接口,它声明了负责调用任意一个方法的invoke()方法:
  Object invoke(Object proxy,Method method,Object[] args) throws Throwable
  参数proxy指定动态代理类实例,参数method指定被调用的方法,参数args 指定向被调用方法传递的参数,invoke()方法的返回值表示被调用方法的返回值。

 

 


分享到:
评论

相关推荐

    java代理机制 JDK动态代理和cglib代理 详解

    Java代理机制是Java编程中一个重要的特性,它允许我们在不修改原有代码的基础上,为已有类增加额外的功能。本文将深入探讨两种主要的Java代理实现:JDK动态代理和CGLIB代理。 一、JDK动态代理 JDK动态代理基于接口...

    Java写http代理服务器

    本主题将深入探讨如何使用Java语言来编写这样的代理服务器。以下是对这个主题的详细解析: 首先,理解HTTP代理服务器的基本原理是必要的。HTTP代理服务器作为客户端与目标服务器之间的中介,它接收客户端的HTTP请求...

    java动态代理机制分析及拓展

    Java 动态代理机制是Java语言提供的一种在运行时创建代理类和代理对象的机制,主要涉及`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。动态代理通常用于实现AOP(面向切面编程)、事件...

    java动态代理类的实例

    Java动态代理是Java语言提供的一种高级特性,它允许我们在运行时创建一个代理对象来代替某个接口或类的对象,这个代理对象能够对...分析和理解这个文件的内容,可以帮助我们深入理解Java动态代理的更多细节和应用场景。

    Java JDK代理、CGLIB、AspectJ代理分析比较

    ### Java代理技术详解:JDK代理、CGLIB与AspectJ #### 一、代理模式简介 代理模式是一种常见的设计模式,在《Design Patterns in Java》一书中对其有明确的定义:“代理模式为一个对象提供一个代理,以控制对该...

    java动态代理机制

    Java动态代理机制是Java语言提供的一种强大的功能,它允许在运行时创建代理对象来实现特定接口,从而可以灵活地扩展或增强已有代码的功能。在Java中,动态代理主要通过两个类来实现:`java.lang.reflect.Proxy` 和 `...

    java 代理例子 -javaagent,premain方式实现

    Java代理是一种在运行时增强或拦截对象方法调用的技术,它可以让我们在不修改原有代码的情况下,为类添加新的功能或行为。在Java中,代理主要分为两种:静态代理和动态代理。静态代理是通过手动创建代理类来实现的,...

    java代理源码

    Java代理源码主要涉及到的是Java编程中的动态代理和网络代理...通过学习和分析这段源码,开发者不仅可以深化对Java代理和Spring AOP的理解,还能掌握构建Web代理服务器的技术,对于提升网络编程和Web开发技能大有裨益。

    java实现的代理服务器

    Java 实现的代理服务器是一种基于Java编程语言的网络服务,它的主要作用是充当客户端与目标服务器之间的...通过分析`HttpProxy.java`和`SubHttpProxy.java`的代码,我们可以深入学习网络编程和代理服务器的相关知识。

    Java动态代理机制分析

    - **日志和监控**:代理可以在方法调用前后记录日志,或者统计方法的执行时间,用于性能分析。 - **事务管理**:在开始方法调用前开启事务,结束后提交或回滚事务。 - **缓存**:代理可以实现缓存逻辑,避免重复计算...

    lotus Domino BS开发 通过java 代理导出excel.doc

    本教程将聚焦于如何利用Java代理来实现Excel文档的导出。 Lotus Domino是一款强大的协作软件,它提供了丰富的开发环境,包括服务器端的LotusScript和客户端的JavaScript,但在此场景下,我们使用的是Java代理,因为...

    Java设计模式-代理模式例子

    源码分析可以帮助我们更好地理解代理模式的实现细节,并能将其运用到自己的项目中,提升代码的可扩展性和可维护性。 通过学习和实践代理模式,开发者可以更好地理解和掌握面向对象设计原则,如单一职责原则和开闭...

    java网络代理源代码

    Java网络代理源代码是用于创建一个代理服务器的程序,它可以帮助开发者在调试和监控网络数据时获取必要的信息。这个源代码特别适用于理解如何利用Java的Socket编程实现网络代理功能。以下将详细介绍Java Socket和...

    java动态代理详细解析

    Java动态代理是一种编程技术,主要用于在运行时创建一个新的对象,该对象可以作为现有接口的实现。动态代理的主要目的是为了在不修改原有代码的基础上,为已有的接口或类添加额外的功能,比如日志、事务管理、性能...

    Java Spring代理模式AOP-IOC分析

    Java Spring代理模式AOP-IOC分析 一、代理模式概述 在软件设计中,代理模式是一种常用的设计模式。它可以在不修改原始代码的情况下,扩展或修改原始对象的行为。代理模式可以分为静态代理和动态代理两种。静态代理...

    JAVA代理服务器

    Java代理服务器是一种网络通信工具,它允许客户端(如浏览器)通过代理来访问其他网络资源,提供了额外的安全性、隐私保护以及可能的性能优化。在Java中实现代理服务器,主要是通过Socket编程来完成的。下面我们将...

    用Java实现的代理模式之动态代理

    在Java中,代理模式有静态代理和动态代理两种实现方式。本篇将重点讨论"动态代理",这是一种在运行时创建代理对象的技术,使得我们可以在程序运行过程中,根据需要动态地生成具有额外功能的代理类。 动态代理主要由...

Global site tag (gtag.js) - Google Analytics