介绍
提供一种代理来对原有对象的访问。
应用实例:Spring AOP、日志、事务控制。
demo
1、定义一个接口和实现
public interface IService {
/**
* 获取名称为name 的年龄
* @param name
* @return
*/
public Integer getAge(String name);
}
public class ServiceImpl implements IService {
@Override
public Integer getAge(String name) {
if (Objects.equals("jack",name)){
return 18;
} else if (Objects.equals("ma",name)){
return 24;
}
return 20;
}
}
2、实现接口方法的拦截,打印参数和返回结果等信息
1. JDK 动态代理
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Objects;
@Slf4j
public class MyInvocationHandler implements InvocationHandler {
private IService iService;
public MyInvocationHandler(IService iService) {
this.iService = iService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Objects.equals("getAge",method.getName())){
StopWatch stopWatch = new StopWatch();
log.info("{}.{} start,args:{}",iService.getClass(),method.getName(),args);
stopWatch.start();
int age = (int)method.invoke(iService, args);
stopWatch.stop();
log.info("{}.{} end success,execTime:{},result:{}",iService.getClass(),method.getName(),stopWatch.getTime(),age);
}
return null;
}
}
2. CGLIB代理
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.cglib.proxy.*;
import java.lang.reflect.Method;
import java.util.Objects;
@Slf4j
public class CglibInvocationHandler implements MethodInterceptor {
private Object target;
public CglibInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if (Objects.equals("getAge", method.getName())) {
StopWatch stopWatch = new StopWatch();
log.info("{}.{} start,args:{}", target.getClass(), method.getName(), objects);
stopWatch.start();
int age = (int) method.invoke(target, objects);
stopWatch.stop();
log.info("{}.{} end success,execTime:{},result:{}", target.getClass(), method.getName(), stopWatch.getTime(), age);
}
return null;
}
public static Object getProxy(Object target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new CglibInvocationHandler(target));
return enhancer.create();
}
}
3、测试
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
//jdk 动态代理
IService iService = new ServiceImpl();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(iService);
IService service = (IService) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{IService.class}, myInvocationHandler);
service.getAge("jack");
//cglib 动态代理
/* IService iService = new ServiceImpl();
IService service = (IService) CglibInvocationHandler.getProxy(iService);
service.getAge("jack");*/
}
}
4、运行结果

最后
JDK动态代理的对象必须要实现接口,所以对于一些没有实现接口要被代理的对象,不适用JDK动态代理;cglib是通过继承被代理类,重写方法,织入通知通过动态字节码生成代理类,所以被final修饰的类是不能用cglib动态代理的。Spring的动态代理选择的方式也是根据这个条件来的。
// org.springframework.aop.framework.DefaultAopProxyFactory
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
网友评论