用javassist實現簡單的動態代理

  網上有網友已經實現了該功能,我只是把我的理解說出來,希望對大家有幫助!     

  主要思路:創建一個攔截器接口,裏面有有一個invoke方法,再創建一個能夠生成代理的類,該類的主要作用是生成了一個新類,該新類實現了被代理類接口的每個方法(生成新類的實例時是用javassist)。這個新類裏每個方法都通過反射去調用攔截器中的invoke方法,(而invoke方法中我們會去調用被代理類的方法),所以我們說在代理類裏如果調用了某個方法,它會自動去調用被代理類的方法。不同的是我們可以在invoke方法中調用其它的服務。 比如說我有一個UserManager的接口

  該接口代理:

        public interface UserManager {

 

public void addUser(String name,String password);

 

public void deleteUser(String userID);

 

public void modifyUser(String userID);

 

public String findByID(String userID);

}

有一個實現了UserManager的接口類

public class UserManagerImpl implements UserManager {

public void addUser(String name, String password) { System.out.println("--------------------adduser----------------------"); } public void deleteUser(String userID) { System.out.println("--------------------deleteUser----------------------"); }

public String findByID(String userID) { System.out.println("--------------------findByID----------------------"); return userID; } public void modifyUser(String userID) { System.out.println("--------------------modifyUser----------------------"); }

    那麼我們新生成的類,也就是代理類生成的代碼要是這樣的

public Class userManagerImpl {

 

public void addUser(java.lang.String a0 ,java.lang.String a1){

MyInvocationHandler handle = new SecurityHandler();

Object returnObje = handle.invoke(Class.forName("UserManagerImpl").newInstance(),Class.forName("UserManagerImpl").getMethods()[0],new Object[]{($w)a0,($w)a1});

}

public java.lang.String findByID(java.lang.String a0){

MyInvocationHandler handle = new SecurityHandler();

Object returnObje = handle.invoke(Class.forName("UserManagerImpl").newInstance(),Class.forName("UserManagerImpl").getMethods()[1],new Object[]{($w)a0});

return (java.lang.String)returnObje;

}

public void deleteUser(java.lang.String a0){

MyInvocationHandler handle = new SecurityHandler();

Object returnObje = handle.invoke(Class.forName("UserManagerImpl").newInstance(),Class.forName("UserManagerImpl").getMethods()[2],new Object[]{($w)a0});

}

public void modifyUser(java.lang.String a0){

MyInvocationHandler handle = new SecurityHandler();

Object returnObje = handle.invoke(Class.forName("UserManagerImpl").newInstance(),Class.forName("UserManagerImpl").getMethods()[3],new Object[]{($w)a0});

}

 

}

 

返回該類的實例,也就是代理類的實例,它其實就是實現了UserManager接口的類,在調用它相應的方法,就會去調用實現了個人攔截器中的invoke方法。也就是達到代理的目的。

 

      小例子:

 

         第一步:創建一個MyInvocationHandler類,攔截器接口類

     import java.lang.reflect.Method;

/**

 * 構建攔截器接口

 *

 */

public interface MyInvocationHandler {

 

public Object invoke(Object Proxy,Method method,Object args[]);

 

 

}

 

 

               第二步:創建一個MyProxy類,代理類,生成目標類的代理。

              public class MyProxy {

 

// 生成代理類的後綴名

public final static String PROXY_SUFFIX_NAME = "$proxy";

 

// 防止生成的代理類重名

public static int proxyIndex = 1;

 

public Object newInstance(Object target,MyInvocationHandler invocationHandler) throws SecurityException, NotFoundException, InstantiationException, IllegalAccessException, CannotCompileException, ClassNotFoundException{

// targetInte 被代理類接口的名字

String targetInte = target.getClass().getInterfaces()[0].getName();

// invocationInte 攔截器接口的名字

String invocationInte = invocationHandler.getClass().getInterfaces()[0].getName();

// nvocationImpl 攔截器實現類的名字

String invocationImpl = invocationHandler.getClass().getName();

// 被代理類的名字

String targetImpl = target.getClass().getName();

 

return generProxy(targetInte,invocationInte,invocationImpl,targetImpl);

}

/**

* @param targetInte

*            被代理類接口的名字

* @param invocationInte

*            攔截器接口的名字

* @param invocationImpl

*            攔截器實現類的名字

* @param targetImpl

*            被代理類的名字

* @return Object 返回代理類

* @throws NotFoundException

* @throws CannotCompileException

* @throws IllegalAccessException

* @throws InstantiationException

* @throws ClassNotFoundException

* @throws SecurityException

*/

 

public static Object generProxy(String targetInte,String invocationInte,String invocationImpl,String targetImpl) throws NotFoundException, InstantiationException, IllegalAccessException, CannotCompileException, SecurityException, ClassNotFoundException {

ClassPool cp = ClassPool.getDefault();

// 根據接口名得到該接口的一個instance

CtClass proxyInte = cp.getCtClass("UserManager");

// 代理的名字

String proxyName = targetInte + PROXY_SUFFIX_NAME + proxyIndex++;

// 生成一個類的instance

CtClass proxy = cp.makeClass(proxyName);

proxy.addInterface(proxyInte);

// 循環遍歷接口中的方法,並把每個生成的每個方法加入到代理類中

Method methods[] = Class.forName(targetInte).getMethods();

for(int i=0;i<methods.length;i++) {

generMethod(proxy,methods[i],invocationInte,invocationImpl,targetImpl,i);

}

return (Object)proxy.toClass().newInstance();

}

/**

* 在動態生成的類裏添加方法

* @param proxy

*            動態類的代理

* @param method

*            接口中要修改的方法

* @param InvocationInte

*            攔截器的接口名字

* @param InvocationImpl

*            攔截器的實現類的名字

* @param targetImpl

*            被代理類的方法名

* @param index

*            接口中的第幾個方法

* @return

* @throws CannotCompileException

*/

public static void generMethod(CtClass proxy,Method method,String invocationInte,String invocationImpl,String targetImpl,int index) throws CannotCompileException{

String methodBody = generMethodBody(method,invocationInte,invocationImpl,targetImpl,index);

CtMethod newMethod = CtNewMethod.make(methodBody,proxy);

proxy.addMethod(newMethod);

}

 

/*

* 構建方法體 @param method 接口中要重寫的方法 @param InvocationInte 攔截器的接口名字 @param

* InvocationImpl 攔截器的實現的名字 @param targetImpl 被代理類的方法名 @param index

* 接口中的第幾個方法 @return String 生成的方法

*/

public static String generMethodBody(Method method,String invocationInte,String invocationImpl,String targetImpl,int index){

StringBuffer methodCode = new StringBuffer();

// 方法的訪問類型,因爲是接口中的方法,所以一律是public

String visit = new String("public");

methodCode.append(visit);

 

// 得到該方法的返回值類型

String returnType = method.getReturnType().getName();

methodCode.append(" "+returnType);

 

// 得到該方法的名字

String methodName = method.getName();

methodCode.append(" "+methodName + "(");

 

// 得到該方法的參數類型和

Class parameterType[] = method.getParameterTypes();

for(int i=0; i<parameterType.length; i++) {

if(i == parameterType.length - 1) {

methodCode.append(parameterType[i].getName()+" a"+i);

}else {

methodCode.append(parameterType[i].getName()+" a"+i+" ,");

}

}

methodCode.append(")");

// 得到該方法的異常

Class ExceptionType[] = method.getExceptionTypes();

if(ExceptionType.length > 0) {

methodCode.append("throws");

for(int i=0;i<ExceptionType.length;i++) {

if(i == ExceptionType.length - 1) {

methodCode.append(" "+ExceptionType[i]);

}else {

methodCode.append(" "+ExceptionType[i]+",");

}

}

}

// 構建方法體

methodCode.append("{/n");

methodCode.append(invocationInte+" handle = new "+ invocationImpl + "();/n");

methodCode.append("Object returnObje = handle.invoke(Class.forName(/""+targetImpl+"/""+").newInstance(),Class.forName(/""+targetImpl+"/").getMethods()["+index+"],");

// 構建參數的Object[]

if(parameterType.length>0) {

methodCode.append("new Object[]{");

for(int i=0;i<parameterType.length;i++) {

if(i == parameterType.length - 1) methodCode.append("($w)a" + i );   

           else methodCode.append("($w)a" + i + ",");

}

}

if(parameterType.length>0) methodCode.append("});/n");

else methodCode.append("null});/n");

// 處理返回值

if(method.getReturnType().isPrimitive()) {   

            if(method.getReturnType().equals(Boolean.TYPE)) methodCode.append("return ((Boolean)returnObj).booleanValue();/n");   

            else if(method.getReturnType().equals(Integer.TYPE)) methodCode.append("return ((Integer)returnObj).intValue();/n");   

            else if(method.getReturnType().equals(Long.TYPE)) methodCode.append("return ((Long)returnObj).longValue();/n");   

            else if(method.getReturnType().equals(Float.TYPE)) methodCode.append("return ((Float)returnObj).floatValue();/n");   

            else if(method.getReturnType().equals(Double.TYPE)) methodCode.append("return ((Double)returnObj).doubleValue();/n");   

            else if(method.getReturnType().equals(Character.TYPE)) methodCode.append("return ((Character)returnObj).charValue();/n");   

            else if(method.getReturnType().equals(Byte.TYPE)) methodCode.append("return ((Byte)returnObj).byteValue();/n");   

            else if(method.getReturnType().equals(Short.TYPE)) methodCode.append("return ((Short)returnObj).shortValue();/n");   

        } else {   

         methodCode.append("return (" + returnType + ")returnObje;/n");   

        }

methodCode.append("}");

System.out.println(methodCode);

return methodCode.toString();

}

}

 

第三步:創建一個實現了MyInvocationHandler的攔截器

   import java.lang.reflect.Method;

 

public class SecurityHandler implements MyInvocationHandler {

 

public Object invoke(Object Proxy, Method method, Object[] args) {

//System.out.println(method.getName()+" Start-----------------------");

 

Object ret = null;

try{

check();

//在目標方法調用之前做什麼

ret = method.invoke(Proxy, args);

//在目標方法調用之後又做什麼

check();

}catch(Exception e) {

throw new java.lang.RuntimeException(e);

}

//System.out.println(method.getName()+" end-----------------------")

return ret;

}

 

public void check() {

System.out.println("------------check---------------------");

}

}

 

第四步,創建一個接口UserManager接口,上面已有代碼

 

第五步,創建一個實現了UserManager接口的類,UserManagerImpl

 

第六步,寫一個測試類  Client

 

 

import java.lang.reflect.Method;

 

 

public class Client {

 

public static void main(String args[]) throws Exception{

MyProxy proxy = new MyProxy();

//測試生成的方法

// Class log = Class.forName("LoggerOperation");

// System.out.println(handler.generMethodBody(log.getMethod("add", new Class[]{int.class}),"InvocationInte","InvocationImpl","targetImpl",1));

SecurityHandler handler = new SecurityHandler();

UserManager userManager = (UserManager)proxy.newInstance(new UserManagerImpl(), handler) ;

 

userManager.addUser("zhangsan", "123456");

System.out.println(userManager.findByID("123"));

}

}

 

 

運行結果:

 

------------check---------------------

--------------------adduser----------------------

------------check---------------------

------------check---------------------

--------------------findByID----------------------

------------check---------------------

123

 

 

不足之處:1、如果一個類實現了多個接口,則只能實現第一個接口中的方法

               2、如果我的一個實現了MyinvocationHandler類是這樣的,那麼調用時,有錯

 

 

import java.lang.reflect.Method;

 

import javassist.CannotCompileException;

import javassist.NotFoundException;

 

public class SecurityHandler implements MyInvocationHandler {

 

private Object target;

private Object operator;

 

/*

* @param interfaceClassName String 要動態代理的接口類名, e.g test.StudentInfoService

* @param classToProxy String 要動態代理的接口的實現類的類名, e.g

* test.StudentInfoServiceImpl @param interceptorHandlerImplClassName String

* 用戶提供的攔截器接口的實現類的類名 @return Object 返回某個接口的動態代理對象 @throws

* InstantiationException @throws IllegalAccessException @throws

* NotFoundException @throws CannotCompileException @throws

* ClassNotFoundException

*/

public Object newProxy(Object target, Object operator, MyInvocationHandler invocationHandler) throws Exception {

this.target = target;

this.operator = operator;

 return new MyProxy().newInstance(operator,this);

}

 

public Object invoke(Object obj, Method method, Object[] args)

throws Throwable {

Object ret = null;

try {

//方法執行前,用反射調用before方法

Method before = this.operator.getClass().getDeclaredMethod("insertBefore", new Class[]{Method.class});

before.invoke(this.operator, method);

//方法執行時

if(method.getName().equals("addUser")){

securityHandler();

}

 

ret = method.invoke(obj, args);

//方法執行後

Method after = this.operator.getClass().getDeclaredMethod("insertAfter", new Class[]{Method.class});

after.invoke(this.operator, method);

}catch(Exception e) {

e.printStackTrace();

throw new java.lang.RuntimeException(e);

}

return ret;

}

 

public void securityHandler(){

System.out.println("---------------securityHandler()-----------------------");

}

}

 

不懂之處:爲什麼方法中的參數前要加個$w呢?

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章