Java代理
2018-12-21 本文已影响0人
胖小白_d797
1.简介
java 代理主要为了解决在客户端调用服务时,加入一些前置或后置处理逻辑。
代理类通过提供与委托类相同的接口,在接收到客户端调用后,代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
Java代理主要实现方式:
- 1.jdk动态代理 (动态AOP)
- 2.cglib动态字节码生成
2.jdk动态代理
使用Proxy.newProxyInstance生成动态代理
// 接口
public interface IUserDao {
boolean login(String name, String password) throws RuntimeException;
}
// 实现类
public class UserDaoImpl implements IUserDao {
@Override
public boolean login(String name, String password) throws RuntimeException{
return "wonking".equals(name) && "666".equals(password);
}
}
动态代理
public class ProxyFactory {
private ProxyFactory(){
}
public static <T> Object getProxyInstance(final T t){
return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 代理类为委托类做的预处理
System.out.println("-----begin transaction-----");
Object returnValue=null;
try{
// 调用委托类本身的实现
returnValue=method.invoke(t, args);
}catch (Exception e){
// 代理类为委托类做的异常处理
System.out.println("-----do rollback-----");
}
// 代理类为委托类做的后处理
System.out.println("-----finish transaction-----");
return returnValue==null ? false : returnValue;
}
});
}
}
使用代理:
public class ApplicationProxy {
public static void main(String[] args) {
UserDaoImpl target=new UserDaoImpl();
IUserDao proxy= (IUserDao) ProxyFactory.getProxyInstance(target);
Object result=proxy.login(null,"666");
}
}
2.cglib动态字节码生成
public class CglibProxyTest {
public static void main(String[] args) {
IUserDao userDao = new UserDaoImpl();
//创建一个织入器
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(IUserDao.class);
//设置需要织入的逻辑
enhancer.setCallback(new LogIntercept(userDao));
//使用织入器创建子类
IUserDao proxy = (IUserDao) enhancer.create();
proxy.login(null,"666");
}
public class LogIntercept implements MethodInterceptor {
private Object targetObj;
public LogIntercept(Object targetObj) {
this.targetObj = targetObj;
}
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//执行原有逻辑
Object rev = proxy.invoke(targetObj, args);
//执行织入的日志
if (method.getName().equals("login")) {
System.out.println("记录login日志");
}
return rev;
}
}
3. 自定义类加载器
Javassist是一个开源的分析、编辑和创建Java字节码的类库。
Javassist中最为重要的是ClassPool,CtClass ,CtMethod 以及 CtField这几个类。
-
ClassPool
:一个基于HashMap实现的CtClass对象容器,其中键是类名称,值是表示该类的CtClass对象。默认的ClassPool使用与底层JVM相同的类路径,因此在某些情况下,可能需要向ClassPool添加类路径或类字节。 -
CtClass
:表示一个类,这些CtClass对象可以从ClassPool获得。 -
CtMethods
:表示类中的方法。 -
CtFields
:表示类中的字段。
通过 CtMethods. insertBefore 和 CtMethods. insertAfter 修改类方法实现.
public class ClassLoaderListener implements Translator {
public void start(ClassPool pool) throws NotFoundException, CannotCompileException {
}
public void onLoad(ClassPool pool, String classname) {
if (!"com.wulouhua.learn.proxy.service.impl.UserDaoImpl".equals(classname)) {
return;
}
try {
CtClass cc = pool.get(classname);
CtMethod m = cc.getDeclaredMethod("login");
m.insertBefore("{ System.out.println(\"记录日志\"); }");
} catch (NotFoundException e) {
} catch (CannotCompileException e) {
}
}
public static void main(String[] args) {
UserDaoImpl dao = new UserDaoImpl();
dao.login("wonking","666");
}
}
public class ClassLoaderBootstrap {
public ClassLoaderBootstrap() {
}
public static void main(String[] args) {
demo(args);
}
static void demo(String[] args) {
ClassPool cp = ClassPool.getDefault();
Loader cl = new Loader();
try {
cl.addTranslator(cp, new ClassLoaderListener());
cl.run("com.wulouhua.learn.proxy.service.ways.javassist.ClassLoaderListener", args);
} catch (NotFoundException var4) {
var4.printStackTrace();
} catch (CannotCompileException var5) {
var5.printStackTrace();
} catch (Throwable var6) {
var6.printStackTrace();
}
}
}
Translator