網上有網友已經實現了該功能,我只是把我的理解說出來,希望對大家有幫助!
主要思路:創建一個攔截器接口,裏面有有一個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呢?