JAVA的動態代理機制及Spring的實現方式

JAVA 代理實現

代理的實現分動態代理和靜態代理,靜態代理的實現是對已經生成了的JAVA類進行封裝。java

動態代理則是在運行時生成了相關代理累,在JAVA中生成動態代理通常有兩種方式。spring

JDK自帶實現方法

JDK實現代理生成,是用類 java.lang.reflect.Proxy, 實現方式以下express

EX:測試

public class JDKProxy {

      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;

                              }

                        });

      }

}

測試代理類方法spa

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實現代理的目標類必須有實現接口.net

2, 生成出來的代理類爲接口實現類,和目標類不能進行轉換,只能轉爲接口實現類進行調用代理

明顯特色:經過此方法生成出來的類名叫作 $Proxy0code

用CGLIB包實現

CGLIB是一個開源項目,官方網址是:http://cglib.sourceforge.net/,能夠去上面下載最新JAR包,xml

本項目用的是cglib-3.0.jar對象

本項目還加入了依賴JAR包asm-4.0.jar,asm-util-4.0.jar

實現方式以下

EX:

測試代理類方法

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.");

      }

}

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();

      }

}

1, CGLIB實現方式是對代理的目標類進行繼承

2, 生成出了的代理類能夠沒方法,生成出來的類能夠直接轉換成目標類或目標類實現接口的實現類,因JAVA向上轉換

明顯特色:經過輸出看出,看出生成出的代理類的parent類爲代理的目標類

 

Spring  AOP的代理類機制分析

 

在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開源項目生成的攔截類的子類.

相關文章
相關標籤/搜索