Java动态代理的两种实现方法


      代理的实现分动态代理和静态代理静态代理的实现是对已经生成了的JAVA类进行封装。

      动态代理则是在运行时生成了相关代理类,在JAVA中生成动态代理一般有两种方式:JDK自带实现方法和使用CGLIB包实现。

jdk动态代理实现

      JDK实现代理生成是用类 java.lang.reflect.Proxy, 实现方式如下:

public static Object getPoxyObject(final Object c) { 
  return Proxy.newProxyInstance(c.getClass().getClassLoader(), 
        c.getClass().getInterfaces(),// JDK实现动态代理但JDK实现必须需要接口 
        new InvocationHandler() { 
             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
          // TODO Auto-generated method stub 
          Object reObj = null; 
          System.out.print("you say: "); 
          reObj = method.invoke(c, args); 
          System.out.println(" [" + Calendar.getInstance().get(Calendar.HOUR) + ":" 
          + Calendar.getInstance().get(Calendar.MINUTE) + " " 
          +  Calendar.getInstance().get(Calendar.SECOND) + "]"); 
          return reObj; 
         } 
    }); 
 } 
}

      测试代理类方法

public class TestForPoxy { 
    public static void main(String[] args) { 
        ServiceTest service = new ServiceTestImpl(); 
        System.out.println(service.getClass().getSimpleName()); 
        ServiceTest poxyService = (ServiceTest) 
        JDKProxy.getPoxyObject(service); 
        System.out.println(poxyService.getClass().getSuperclass()); 
        poxyService.saySomething("hello,My QQ code is 107966750."); 
        poxyService.saySomething("what 's your name?"); 
        poxyService.saySomething("only for test,hehe."); 
    } 
}
  1. Proxy实现代理的目标类必须有实现接口 ;
  2. 生成出来的代理类为接口实现类和目标类不能进行转换只能转为接口实现类进行调用;

      明显特点:通过此方法生成出来的类名叫做 $Proxy0。

cglib动态代理实现

      CGLIB是一个开源项目官方网址是http://cglib.sourceforge.net/,可以去上面下载最新JAR包

      本项目用的是cglib-3.0.jar 、还加入了依赖JAR包asm-4.0.jarasm-util-4.0.jar ;实现方式如下:

public class CGLIBProxy { 
    public static Object getPoxyObject(Object c) { 
        Enhancer enhancer = new Enhancer(); 
        enhancer.setSuperclass(c.getClass()); 
        enhancer.setCallback(new MethodInterceptor() { 
            public Object intercept(Object arg0, Method arg1, Object[] 
                arg2, MethodProxy proxy) throws Throwable { 
                System.out.print("you say: "); 
                proxy.invokeSuper(arg0, arg2); 
                System.out.println(" [" + 
                Calendar.getInstance().get(Calendar.HOUR) + ":" 
                +  Calendar.getInstance().get(Calendar.MINUTE) + " " + 
                Calendar.getInstance().get(Calendar.SECOND) 
                + "]"); 
                return null; 
            } 
        }); 
        return enhancer.create(); 
    } 
}

      测试代理类方法:

public class TestForPoxy { 
    public static void main(String[] args) { 
        ServiceTest service = new ServiceTestImpl(); 
        System.out.println(service.getClass().getSimpleName()); 
        //  ServiceTest poxyService = (ServiceTest) 
        JDKProxy.getPoxyObject(service); 
        ServiceTest poxyService = (ServiceTest) CGLIBProxy.getPoxyObject(service); 
        System.out.println(poxyService.getClass().getSuperclass()); 
        poxyService.saySomething("hello,My QQ code is 107966750."); 
        poxyService.saySomething("what 's your name?"); 
        poxyService.saySomething("only for test,hehe."); 
    } 
}
  1. CGLIB实现方式是对代理的目标类进行继承 ;
  2. 生成出了的代理类可以没方法,生成出来的类可以直接转换成目标类或目标类实现接口的实现类,因JAVA向上转换;

      明显特点:通过输出,看出生成出的代理类的parent类为代理的目标类 。

SpringAOP的代理类机制分析

      在spring中,bean都是由动态代理生成出来的。那么到底是用JDK的Proxy类实现呢?还是用CGLIB方式实现呢?

      AOP Spring需要的依赖JAR包有:

spring-asm-3.2.0.M1.jar 
spring-beans-3.2.0.M1.jar 
spring-context-3.2.0.M1.jar 
spring-core-3.2.0.M1.jar 
spring-expression-3.2.0.M1.jar 
spring-aop-3.2.0.M1.jar 
spring-aspects-3.2.0.M1.jar 
commons\commons-logging-1.1.1\commons-logging-1.1.1.jar 
aopalliance\aopalliance.jar 
lib\aspectjweaver.jar 

实现AOP

      先简单的实现AOP,配置如下:

<?xml version="1.0" encoding="utf-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xsi:schemaLocation=" 
    http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
    http://www.springframework.org/schema/aop   
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"> 
    <bean id="test" class="org.ben.spring.service.Test" /> 
    <bean id="aspectBean" class="org.ben.spring.TestAspect" /> 
    <!-- 对Test类进行AOP拦截 --> 
    <aop:config> 
        <aop:aspect id="TestAspect" ref="aspectBean"> 
            <!--配置切面--> 
            <aop:pointcut id="businessService"  expression="execution(* 
                org.ben.spring.service.Test.say(..))" /> 
            <aop:before pointcut-ref="businessService"  method="doBefore" /> 
            <aop:after pointcut-ref="businessService" method="doAfter" /> 
        </aop:aspect> 
    </aop:config> 
</beans>  

      然后进行运行结果如下表示AOP拦截成功

      AOP测试类:

public class TestBeans { 
    public static void main(String[] args) { 
        ApplicationContext ctx = new 
        ClassPathXmlApplicationContext("test.xml"); 
        Test test=(Test) ctx.getBean("test"); 
        System.out.println(test.getClass().getSimpleName()); 
        test.say(); 
    } 
} 

      输出:

do something in befor 
welcome for test 
do something in after

打印代理类的生成方式

      第一种情况, Test不实现任何接口,代码如下

public class Test { 
    public void say() { 
         System.out.println("welcome for testMy QQ is 107966750"); 
    } 
} 

      在TestBeans中加入打印当前对象的名称,如下:

ApplicationContext ctx = new ClassPathXmlApplicationContext("test.xml"); 
Test test=(Test) ctx.getBean("test"); 
System.out.println(test.getClass().getSimpleName()); 
test.say(); 

      输出:

Test$$EnhancerByCGLIB$$4791b36c 
super class is class org.ben.spring.service.Test 
do something in befor 
welcome for test 
do something in after 

      明显看到用了AOP之后输出的是代理类对象Test . EnhancerByCGLIB.bb9b6a7c.而且它的父类是我们的代理目标类。说明是有CGLIB生成的。

      第二种情况,XML的配置不变,改变代理目标类Test的实现方法如下 :

public class Test implements TestInter{ 
    public void say() { 
        System.out.println("welcome for testMy QQ is 107966750"); 
    } 
}

      和原来不同的是多继承了一个接口,接口中定义了say()方, 在TestBeans中加入打印当前对象的名称,如下:

ApplicationContext ctx = new ClassPathXmlApplicationContext("test.xml"); 
TestInter test=(TestInter) ctx.getBean("test"); 
System.out.println(test.getClass().getSimpleName()); 
System.out.println("super class is "+test.getClass().getSuperclass()); 
test.say();

      输出:

$Proxy0 
super class is class java.lang.reflect.Proxy 
do something in befor 
welcome for test,My QQ is 107966750 
do something in after

结论

      Spring AOP中,当拦截对象实现了接口时,生成方式是用JDK的Proxy类。当没有实现任何接口时,用的是GCLIB开源项目生成的拦截类的子类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值