- 先來看看靜態代理
- User.java
- package com.dao;
-
- /**
- * 定義一個用戶接口
- *
- * @author Administrator
- *
- */
- public interface User {
- // 說話方法
- public void say();
-
- }
- UserImp1.java
- package com.imp
- public class UserImp1 implements User{
- @Override
- public void say(){
- System.out.println("Now,I am say....");
- }
- }
-
- UserProxy.java
- package com.imp
- public class UserProxy implements User{
- private UserImp1 userImp1;
- public UserProxy(UserImp1 userImp1){
- this.userImp1=userImp1;
- }
- @Override
- public void say(){
- System.out.println("說話以前。。。。");
- userImp1.say();
- System.out.println("說話以後。。。。。");
- }
- }
- TestUser.java
- package com.test
- public class TestUser{
- public static void main(String[] args){
- UserImp1 userImp1=new UserImp1();
- UserProxy userProxy=new UserProxy(userImp1);
- userProxy.say();
- }
- }
觀察代碼咱們能夠發現每一個代理類只能爲一個接口服務,這樣一來程序開發中必然會產生過多的代理。並且,全部的代理操做除了所調用的方法不同以外,其餘的操做同樣的,則此時確定是重複代碼。解決這一問題最好的作法是能夠經過一個代理類完成所有的代理功能,那麼此時就必須使用動態代理來完成】 java
JDK動態代理包含一個類和一個接口: node
- 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接口的子類實例 ide
Ps:類加載器
在Proxy類中的newProxyInstance()方法中須要一個ClassLoader類的實例,ClassLoader實際上對應的是類加載器,在Java中主要有一下三種類加載器;
Booststrap ClassLoader:此加載器採用C++編寫,通常開發中是看不到的;
Extendsion ClassLoader:用來進行擴展類的加載,通常對應的是jre\lib\ext目錄中的類;
AppClassLoader:(默認)加載classpath指定的類,是最常使用的是一種加載器。 this
動態代理
與靜態代理類對照的是動態代理類,動態代理類的字節碼在程序運行時由Java反射機制動態生成,無需程序員手工編寫它的源代碼。動態代理類不只簡化了編程工做,並且提升了軟件系統的可擴展性,由於Java 反射機制能夠生成任意類型的動態代理類。java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動態代理類的能力。 spa
動態代理示例:
- 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;
-
- /**
- * JDK動態代理代理類
- *
- * @author student
- *
- */
- public class BookFacadeProxy implements InvocationHandler {
- private Object target;
- /**
- * 綁定委託對象並返回一個代理類
- * @param target
- * @return
- */
- public Object bind(Object target) {
- this.target = target;
- //取得代理對象
- return Proxy.newProxyInstance(target.getClass().getClassLoader(),
- target.getClass().getInterfaces(), this); //要綁定接口(這是一個缺陷,cglib彌補了這一缺陷)
- }
-
- @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;
- }
-
- }
3 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 .net
- package net.battier.dao.impl;
-
- /**
- * 這個是沒有實現接口的實現類
- *
- * @author student
- *
- */
- 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;
-
- /**
- * 使用cglib動態代理
- *
- * @author student
- *
- */
- public class BookFacadeCglib implements MethodInterceptor {
- private Object target;
-
- /**
- * 建立代理對象
- *
- * @param target
- * @return
- */
- 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();
- }
- }
固然,
Cglib來實現動態代理必須引入cglib-nodep.jar包