JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現加強,但由於採用的是繼承,因此不能對final修飾的類進行代理。 java
JAVA的動態代理
代理模式
代理模式是經常使用的java設計模式,他的特徵是代理類與委託類有一樣的接口,代理類主要負責爲委託類預處理消息、過濾消息、把消息轉發給委託類,以及過後處理消息等。代理類與委託類之間一般會存在關聯關係,一個代理類的對象與一個委託類的對象關聯,代理類的對象自己並不真正實現服務,而是經過調用委託類的對象的相關方法,來提供特定的服務。
按照代理的建立時期,代理類能夠分爲兩種。
靜態代理:由程序員建立或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。
動態代理:在程序運行時,運用反射機制動態建立而成。 程序員
首先看一下靜態代理:
一、Count.java 編程
- package net.battier.dao;
-
- public interface Count {
-
- public void queryCount();
-
-
- public void updateCount();
-
- }
二、CountImpl.java 設計模式
- package net.battier.dao.impl;
-
- import net.battier.dao.Count;
-
- public class CountImpl implements Count {
-
- @Override
- public void queryCount() {
- System.out.println("查看帳戶方法...");
-
- }
-
- @Override
- public void updateCount() {
- System.out.println("修改帳戶方法...");
-
- }
-
- }
-
- 、CountProxy.java
- package net.battier.dao.impl;
-
- import net.battier.dao.Count;
-
- public class CountProxy implements Count {
- private CountImpl countImpl;
-
-
- public CountProxy(CountImpl countImpl) {
- this.countImpl = countImpl;
- }
-
- @Override
- public void queryCount() {
- System.out.println("事務處理以前");
-
- countImpl.queryCount();
- System.out.println("事務處理以後");
- }
-
- @Override
- public void updateCount() {
- System.out.println("事務處理以前");
-
- countImpl.updateCount();
- System.out.println("事務處理以後");
-
- }
-
- }
三、TestCount.java ide
- package net.battier.test;
-
- import net.battier.dao.impl.CountImpl;
- import net.battier.dao.impl.CountProxy;
-
- public class TestCount {
- public static void main(String[] args) {
- CountImpl countImpl = new CountImpl();
- CountProxy countProxy = new CountProxy(countImpl);
- countProxy.updateCount();
- countProxy.queryCount();
-
- }
- }
觀察代碼能夠發現每個代理類只能爲一個接口服務,這樣一來程序開發中必然會產生過多的代理,並且,全部的代理操做除了調用的方法不同以外,其餘的操做都同樣,則此時確定是重複代碼。解決這一問題最好的作法是能夠經過一個代理類完成所有的代理功能,那麼此時就必須使用動態代理完成。
再來看一下動態代理:
JDK動態代理中包含一個類和一個接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
參數說明:
Object proxy:指被代理的對象。
Method method:要調用的方法
Object[] args:方法調用時所須要的參數 工具
能夠將InvocationHandler接口的子類想象成一個代理的最終操做類,替換掉ProxySubject。 測試
Proxy類:
Proxy類是專門完成代理的操做類,能夠經過此類爲一個或多個接口動態地生成實現類,此類提供了以下的操做方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
參數說明:
ClassLoader loader:類加載器
Class<?>[] interfaces:獲得所有的接口
InvocationHandler h:獲得InvocationHandler接口的子類實例 this
Ps:類加載器
在Proxy類中的newProxyInstance()方法中須要一個ClassLoader類的實例,ClassLoader實際上對應的是類加載器,在Java中主要有一下三種類加載器;
Booststrap ClassLoader:此加載器採用C++編寫,通常開發中是看不到的;
Extendsion ClassLoader:用來進行擴展類的加載,通常對應的是jre\lib\ext目錄中的類;
AppClassLoader:(默認)加載classpath指定的類,是最常使用的是一種加載器。 spa
動態代理
與靜態代理類對照的是動態代理類,動態代理類的字節碼在程序運行時由Java反射機制動態生成,無需程序員手工編寫它的源代碼。動態代理類不只簡化了編程工做,並且提升了軟件系統的可擴展性,由於Java 反射機制能夠生成任意類型的動態代理類。java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動態代理類的能力。 設計
動態代理示例:
一、BookFacade.java
- package net.battier.dao;
-
- public interface BookFacade {
- public void addBook();
- }
二、BookFacadeImpl.java
- package net.battier.dao.impl;
-
- import net.battier.dao.BookFacade;
-
- public class BookFacadeImpl implements BookFacade {
-
- @Override
- public void addBook() {
- System.out.println("增長圖書方法。。。");
- }
-
- }
-
- 、BookFacadeProxy.java
-
- package net.battier.proxy;
-
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
-
- public class BookFacadeProxy implements InvocationHandler {
- private Object target;
-
- public Object bind(Object target) {
- this.target = target;
-
- return Proxy.newProxyInstance(target.getClass().getClassLoader(),
- target.getClass().getInterfaces(), this);
- }
-
- @Override
-
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Object result=null;
- System.out.println("事物開始");
-
- result=method.invoke(target, args);
- System.out.println("事物結束");
- return result;
- }
-
- }
三、TestProxy.java
- package net.battier.test;
-
- import net.battier.dao.BookFacade;
- import net.battier.dao.impl.BookFacadeImpl;
- import net.battier.proxy.BookFacadeProxy;
-
- public class TestProxy {
-
- public static void main(String[] args) {
- BookFacadeProxy proxy = new BookFacadeProxy();
- BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
- bookProxy.addBook();
- }
-
- }
可是,JDK的動態代理依靠接口實現,若是有些類並無實現接口,則不能使用JDK代理,這就要使用cglib動態代理了。
Cglib動態代理
JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現加強,但由於採用的是繼承,因此不能對final修飾的類進行代理。
示例
一、BookFacadeCglib.java
- package net.battier.dao;
-
- public interface BookFacade {
- public void addBook();
- }
二、BookCadeImpl1.java
- package net.battier.dao.impl;
-
- public class BookFacadeImpl1 {
- public void addBook() {
- System.out.println("增長圖書的普通方法...");
- }
- }
三、BookFacadeProxy.java
- package net.battier.proxy;
-
- import java.lang.reflect.Method;
-
- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
-
- public class BookFacadeCglib implements MethodInterceptor {
- private Object target;
-
-
- public Object getInstance(Object target) {
- this.target = target;
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(this.target.getClass());
-
- enhancer.setCallback(this);
-
- return enhancer.create();
- }
-
- @Override
-
- public Object intercept(Object obj, Method method, Object[] args,
- MethodProxy proxy) throws Throwable {
- System.out.println("事物開始");
- proxy.invokeSuper(obj, args);
- System.out.println("事物結束");
- return null;
-
-
- }
-
- }
四、TestCglib.java
- package net.battier.test;
-
- import net.battier.dao.impl.BookFacadeImpl1;
- import net.battier.proxy.BookFacadeCglib;
-
- public class TestCglib {
-
- public static void main(String[] args) {
- BookFacadeCglib cglib=new BookFacadeCglib();
- BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
- bookCglib.addBook();
- }
- }