网上有网友已经实现了该功能,我只是把我的理解说出来,希望对大家有帮助!
主要思路:创建一个拦截器接口,里面有有一个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呢?