`
dylan0514sina.cn
  • 浏览: 95023 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

commons-proxy的使用

阅读更多
commons-proxy的使用

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

代理主要用途有懒加载,安全,事务,日志,行为监控等对个方面。commons-proxy中提供了代理的多种生成工具,比如用JDK动态代理,CGLIB和Javassist。首先,先介绍工具的实现原理,然后再介绍对应的commons-proxy中对工具的运用[list]
  • JDK 动态代理
  • JDK动态代理主要涉及两个类 Proxy,InvocationHandler.Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类.
    static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 

    InvocationHandler接口中只有一个方法,一般我们会实现这个类,重写这个唯一的方法invoke(),当用Proxy创建代理对象(代理类的名字是不可知的,这也是动态代理与静态代理的区别)时,传入了一个InvocationHandler参数。当调用代理对象的任何方法放入时候,会自动跳转到调用InvocationHandler中的invoke方法(你可以在invoke()方法内设置断点跟踪)
    Object invoke(Object proxy, Method method, Object[] args)

    使用JDK动态代理步骤:
  • 首先,必须有一个实现了接口的对象(即要代理的对象)
  • 其次,先实现InvocationHandler接口,并且在此实现中得到代理的真正对象(一般通过构造函数或setter方法注入,由成员变量接受);然后调用Proxy的newProxyInstance,创建代理对象。
  • 接口Animal,实现类Dog,InvocationHandler的实现MyHandler(如无特别说明,下面举例以此为据)
    package com.bstek.dylan;
    
    public interface Animal {
    	
    	
    	public void eat();
    	
    }

    package com.bstek.dylan;
    
    public class Dog implements Animal {
    
    	public void eat() {
    		System.out.println("I am eating ");
    
    	}
    
    }
    package com.bstek.dylan;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class MyHandler implements InvocationHandler {
    	
    	
    	
    	private Object target ;
    	
    	public Object bind(Object target) {
    		this.target = target;
    		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    	}
    	public Object invoke(Object proxy, Method method, Object[] args)
    			throws Throwable {
    		// TODO Auto-generated method stub
    		System.out.println("--------ok---------");
    		
    		return method.invoke(target, args);
    	}
    	
    	public static void main(String[] args) {
    		
    		Animal dog = new Dog();
    		
    		dog = (Animal) new MyHandler().bind(dog);
    		
    		dog.eat();
    	}
    }
    结果
    --------ok---------
    I am eating

    Proxy.newProxyInstance()方法内部运行机制:
    代理类名:把接口类加载到JVM,放到内部Set里保存,把接口的完整名字保存,带包名的接口名字,并以把这组接口名称数组转换成List作为key,用于下面生成代理类后保存到内部Map的key.也就是相当于这一组的接口名称对应的一个生成的代理类.主要是从内存里找是否之前已经生成好了这同一组接口的代理类,如果有就直接拿出。这里第一次是需要新建立的,所以开始创建代理,首先检查代理目标接口的访问控制符是否是默认包级别的,如果是就需要给生成的代理类设置目标接口同样的包名,才能默认访问这种级别下的接口。如果这种有默认访问控制标识符的目标接口,又有不同包名的目标接口,则会报出错误。否则其它情况,是给的无包名的代理类,生成的代理类的默认名称是$Proxy开头加Proxy里标识唯一类名的数字,是静态long型变量,每次生成一次代理类会累加
    字节码类: 动态生成class字节码类,该类相当于是Proxy的子类,实现了需要代理的接口方法,并在每个方法里调用了InvocationHandler的invoke方法,而我们自己实现的InvocationHandler接口类里完成了以反射方式最终对目标业务类的接口方法进行调用。所以此种方式实现的动态代理只能代理接口方法,对具体类的代理不能实现。
    ProxyGenerator.generateProxyClass(proxyName, interfaces)
    根据指定接口和代理类名生成class字节数据,再用这代码生成最终类
    proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); 

    commons-proxy中有一个类叫ProxyFactory,它底层用JDK中Proxy.newProxyInstance来创建代理对象的.在以下创建方法中,只看形参,主要有两点区别 1.有无ClassLoader,意思是可以自己指定;如果没有指定,默认是当前线程的ClassLoader(通过Thread.currentThread().getContextClassLoader()获取),传入的ClassLoader就是传入到Proxy.newProxyInstance的ClassLoader形参中。2. 有三种不同类型ObjectProvider,Interceptor ,Invoker
    ProxyFactory创建代理的方法如下
     Object createDelegatorProxy(ClassLoader classLoader, ObjectProvider delegateProvider, Class[] proxyClasses)  
     Object createDelegatorProxy(ObjectProvider delegateProvider, Class[] proxyClasses)  
     Object createInterceptorProxy(ClassLoader classLoader, Object target, Interceptor interceptor, Class[] proxyClasses) 
     Object createInterceptorProxy(Object target, Interceptor interceptor, Class[] proxyClasses)  
     Object createInvokerProxy(ClassLoader classLoader, Invoker invoker, Class[] proxyClasses)  
     Object createInvokerProxy(Invoker invoker, Class[] proxyClasses) 
    

    ObjectProvider作为参数构造了DelegatorInvocationHandler ,这个类实现了InvocationHandler,所以,当目标对象被调用的时候,该类的invoke()方法中就通过ObjectProvider拿到被代理的目标对象,然后调用目标对象上的方法。很显然,由于DelegatorInvocationHandler 在内部构造,invoke()方法根本不可能被重写,所以假如你想在方法前后打印日志,是根本不可能实现的。故ObjectProvider只被简单的作为一个代理实现。同样DelegatorInvocationHandler传入到Proxy.newProxyInstance方法的形参中。
      private static class DelegatorInvocationHandler implements InvocationHandler
        {
            private final ObjectProvider delegateProvider;
            protected DelegatorInvocationHandler( ObjectProvider delegateProvider )
            {
                this.delegateProvider = delegateProvider;
            }
    
            public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable
            {
                try
                {
                    return method.invoke( delegateProvider.getObject(), args );
                }
                catch( InvocationTargetException e )
                {
                    throw e.getTargetException();
                }
            }
        }

    举例
         
    BeanProvider provider = new BeanProvider();
    provider.setBeanClass(Dog.class);
    ProxyFactory factory = new ProxyFactory();
    Animal proxy = (Animal)factory.createDelegatorProxy(provider, provider.getObject().getClass().getInterfaces());
    		proxy.eat();
    结果
    I am eating

    Interceptor和Target(目标对象)作为形参传入InterceptorInvocationHandler,
    同样,InterceptorInvocationHandler实现了InvocationHandler.当调用代理对象方法时,会调用invoke(),其中ReflectionInvocation实现了Invocation

    private static class InterceptorInvocationHandler implements InvocationHandler
        {
            private final Object target;
            private final Interceptor methodInterceptor;
            public InterceptorInvocationHandler( Object target, Interceptor methodInterceptor )
            {
                this.target = target;
                this.methodInterceptor = methodInterceptor;
            }
    
            public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable
            {
                final ReflectionInvocation invocation = new ReflectionInvocation( target, method, args );
                return methodInterceptor.intercept( invocation );
            }
        }

    看以上代码methodInterceptor.intercept( invocation )可知只需要重写 intercept( invocation ),在方法中只需要调用invocation.proceed()即可实现目标对象的方法调用,你可以在invocation.proceed()前后打印日志.ReflectionInvocation的proceed()方法实现(仍然用反射)
     
    public Object proceed() throws Throwable
            {
                try
                {
                    return method.invoke( target, arguments );
                }
                catch( InvocationTargetException e )
                {
                    throw e.getTargetException();
                }
            }

    举例
    public class MyInterceptor implements Interceptor {
    
    	public Object intercept(Invocation invocation) throws Throwable {
    		
    		String method = invocation.getMethod().getName();
    		if(method.equals("eat")) {
    			System.out.println("吃饭");
    		}
    		return invocation.proceed();
    	}
    
    }
          Interceptor interceptor = new MyInterceptor();
    	  ProxyFactory factory = new ProxyFactory();
    	  Animal animal = new Dog();
    	  Animal proxy = (Animal)factory.createInterceptorProxy(animal, interceptor, animal.getClass().getInterfaces());
    		proxy.eat();

    结果
    吃饭
    I am eating 

    Invoker传入InvokerInvocationHandler,可见你只需要重写invoke()。
        private static class InvokerInvocationHandler implements InvocationHandler
        {
            private final Invoker invoker;
            public InvokerInvocationHandler( Invoker invoker )
            {
                this.invoker = invoker;
            }
    
            public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable
            {
                return invoker.invoke( proxy, method, args );
            }
        }

    举例
    public class MyInvoker implements Invoker {
    	
    	private Object target;
    	
    	public MyInvoker(Object target){
    		this.target = target;
    	}
    	public Object invoke(Object proxy, Method method, Object[] arguments)
    			throws Throwable {
    		String methodName = method.getName();
    		if(methodName.equals("eat")) {
    			System.out.println("吃饭");
    		}else if(methodName.equals("defecate")) {
    			System.out.println("排便");
    		}
    		return method.invoke(target, arguments);
    	}
    	public Object getTarget() {
    		return target;
    	}
    	public void setTarget(Object target) {
    		this.target = target;
    	}
    
    }
    	Animal animal = new Dog();
    		Invoker invoker = new MyInvoker(animal);
    		ProxyFactory factory = new ProxyFactory();
    		Animal proxy = (Animal)factory.createInvokerProxy(invoker, animal.getClass().getInterfaces());
    		proxy.eat();

    结果
    吃饭
    I am eating 

    总结:ProxyFactory创建代理有三种方式(不考虑ClassLoader):ObjectProvider,
    Interceptor,Invoker.

    • ObjectProvider接口只有一个Object getObject(),只是提供目标对象ProxyFactory创建代理对象,不能够手动控制方法调用;
    • Interceptor接口只有一个 Object intercept(Invocation invocation)Invocation类中封装了一些信息,比如代理对象,方法,方法参数,方法调用(前面讲的Invocation.process()),可以在intercept中做打印日志,控制方法是否调用等操作;
    • Invoker接口只有一个Object invoke(Object proxy, Method method, Object[] arguments),与intercept不同的是它并没有把proxy,method,arguments和method.invoke()封装为
    • Invocation.process()。

  • CGLIB
  • Javassist

  • [list]
    2
    0
    分享到:
    评论

    相关推荐

      commons-proxy-1.0中文帮助

      commons-proxy1.0的中文帮助文档,本人翻译,请批评指正

      apache开源项目源码commons-proxy-1.0-src(全部高质量代理模式proxy的java源程序)

      apache开源项目源码commons-proxy-1.0-src 全部高质量代理模式proxy的java源程序 java.proxy,代理模式源码,设计模式,apache开源项目源码commons-proxy-1.0-src 各种代理模式操作的工具类源码以及代理模式案例...

      Apache Commons 所有包最新版本 含SRC (6/7)

      commons-attributes-2.2-src.zip commons-attributes-2.2.zip commons-beanutils-1.8.0-BETA-src.zip commons-beanutils-1.8.0-BETA.zip commons-betwixt-0.8-src.zip commons-betwixt-0.8.zip ......

      Apache Commons 所有包最新版本 含SRC (7/7)

      commons-attributes-2.2-src.zip commons-attributes-2.2.zip commons-beanutils-1.8.0-BETA-src.zip commons-beanutils-1.8.0-BETA.zip commons-betwixt-0.8-src.zip commons-betwixt-0.8.zip ......

      Apache Commons 所有包最新版本 含SRC (4/7)

      commons-attributes-2.2-src.zip commons-attributes-2.2.zip commons-beanutils-1.8.0-BETA-src.zip commons-beanutils-1.8.0-BETA.zip commons-betwixt-0.8-src.zip commons-betwixt-0.8.zip ......

      Apache Commons 所有包最新版本 含SRC (2/7)

      commons-attributes-2.2-src.zip commons-attributes-2.2.zip commons-beanutils-1.8.0-BETA-src.zip commons-beanutils-1.8.0-BETA.zip commons-betwixt-0.8-src.zip commons-betwixt-0.8.zip ......

      Apache Commons 所有包最新版本 含SRC (1/7)

      commons-attributes-2.2-src.zip commons-attributes-2.2.zip commons-beanutils-1.8.0-BETA-src.zip commons-beanutils-1.8.0-BETA.zip commons-betwixt-0.8-src.zip commons-betwixt-0.8.zip ......

      Apache Commons 所有包最新版本 含SRC (3/7)

      commons-attributes-2.2-src.zip commons-attributes-2.2.zip commons-beanutils-1.8.0-BETA-src.zip commons-beanutils-1.8.0-BETA.zip commons-betwixt-0.8-src.zip commons-betwixt-0.8.zip ......

      apache-commons源代码2,包括doc,src,jar

      commons-proxy-1.0.zip commons-scxml-0.9-bin.zip commons-transaction-1.2.zip commons-validator-current-bin.zip commons-vfs-2.0.zip jcs-1.3.zip; 这个没有的就在源代码1里面,找好了,下错了骂我

      Apache Commons 所有包最新版本 含SRC (5/7)

      commons-attributes-2.2-src.zip commons-attributes-2.2.zip commons-beanutils-1.8.0-BETA-src.zip commons-beanutils-1.8.0-BETA.zip commons-betwixt-0.8-src.zip commons-betwixt-0.8.zip ......

      commons-dbcp源码

      - `org.apache.commons.dbcp.proxy`:包含用于创建代理连接和代理Statement的类,用于添加额外的监控和控制。 4. 主要类详解: - `BasicDataSource`:这是DBCP的数据源实现,它实现了DataSource接口,提供了配置...

      比较全面的:Jakarta-commons jar包(附: chm参考手册 & 资源简介)

      commons-proxy 创建动态代理的库 commons-scxml commons-transaction 处理多级事务的集合 commons-validator 提供了一个简单的,可扩展的框架来在一个XML文件中定义校验器 (校验方法)和校验规则 commons-vfs ...

      Jakarta commons docs API CHM 格式

      commons-proxy 创建动态代理的库 commons-scxml commons-transaction 处理多级事务的集合 commons-validator 提供了一个简单的,可扩展的框架来在一个XML文件中定义校验器 (校验方法)和校验规则 commons-vfs ...

      commons-beanutils-1.6.zip

      这个"commons-beanutils-1.6.zip"文件包含了Apache Commons BeanUtils库的1.6版本,这是一个早期但仍然广泛使用的版本。在这个版本中,开发者可以找到一系列用于简化JavaBeans操作的类和方法。 Apache Commons ...

      common-proxy-service:Java中的通用网络代理服务

      以后将通过使用事件源和CQRS模式以及Web UI支持审核。 由于Swagger UI和SpringBoot管理界面的集成,因此服务是在1.5.14版本的SpringBoot上构建的。 一旦这些依赖关系变得更加稳定,我将升级到2.x。 依存关系 您...

      java源码:高性能web代理程序 hyk-proxy.rar

      6. **依赖库**:可能会包含第三方库,如Netty(用于高性能网络编程)、Apache Commons IO(处理输入/输出操作)等。 在学习这个项目时,重点应关注以下几个方面: 1. **并发处理**:查看项目如何利用Java的线程池、...

      commons.zip

      Apache Commons系列工具类jar包,不是所有的,但是该有的都有。比如[beanutils][dbcp2][dbutils][email][exec][fileupload][io][imaging][math][proxy][text][net][lang][logging]等

      spring-aop-jar

      - 代理(Proxy):Spring AOP通过代理来实现切面的织入。代理对象负责拦截方法调用并执行相关的通知。 在实际应用中,Spring AOP常用于以下场景: 1. 日志记录:在方法调用前后记录日志信息。 2. 事务管理:确保一...

      java集成flex需要的JAR包

      在CSDN找半天找不到一个全面的,我一生气,传了个全面的上来,包括 backport-util-concurrent.jar commons-httpclient.jar commons-logging.jar ...flex-messaging-proxy.jar flex-messaging-remoting.jar 呵呵

      HttpClent所需jar包

      hostConfig.setProxyHost(new ProxyHost("proxy.example.com", 8080)); httpClient.setTimeout(5000); // 设置连接超时为5秒 ``` 4. 执行请求并获取响应: ```java int statusCode = httpClient.executeMethod...

    Global site tag (gtag.js) - Google Analytics