用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呢?

 

 

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