代理的优点
代理是一种很重要的思想,了解代理的使用对我们的coding很有帮助。使用代理的一些优点:
- 可以做共性的逻辑处理,比如鉴权、日志、事务等等,实际上这也是AOP的作用
- 屏蔽网络差异和复杂性,代理在本地,而实际对象(服务)在其他服务器上,调用本地代理时,由本地代理请求其他服务器(如Dubbo的网络调用)
动态代理的方式
1.JDK动态代理
创建方式:
public interface IServiceFoo {
void sayHello();
}
public class ServiceFooImpl implements IServiceFoo {
@Override
public void sayHello() {
System.out.println("action: ServiceFooImpl.sayHello");
}
}
/**
* java.lang.reflect.InvocationHandler
*/
public class SimpleInvocationHandler implements InvocationHandler {
//被代理的真正的目标对象
private Object realObj;
public SimpleInvocationHandler(Object realObj) {
this.realObj = realObj;
}
/**
*
* @param proxy 代理
* @param method 要调用的方法
* @param args 方法的参数
* @return 方法执行结果
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("entering " + method.getDeclaringClass().getSimpleName() + ":: " + method.getName());
Object result = method.invoke(this.realObj, args);
System.out.println("leaving " + method.getDeclaringClass().getSimpleName()+":: " + method.getName());
return result;
}
}
public class TestA {
public static void main(String[] args) {
IServiceFoo realService = new ServiceFooImpl();
IServiceFoo proxyInstance = getProxy(IServiceFoo.class, realService);
proxyInstance.sayHello();
}
/**
*
* @param targetInterface 被代理的接口
* @param realObject 被代理的接口的实现
* @param <T> type
* @return
*/
private static <T> T getProxy(Class<T> targetInterface, T realObject) {
return (T) Proxy.newProxyInstance(targetInterface.getClassLoader(),//类加载器
new Class[] {targetInterface},//被代理的接口数组
new SimpleInvocationHandler(realObject));//调用处理器
}
}
JDK动态代理就是使用Java的反射包java.lang.reflect
提供的相关API去实现即可:
Proxy/InvocationHandler
1.cglib动态代理
jdk动态代理的局限在于,它只能为接口创建代理,返回的代理对象也只能转换到某个接口类型,如果要代理类,我们需要使用cglib动态代理。创建方式如下:
/**
* import org.springframework.cglib.proxy.Enhancer;
* import org.springframework.cglib.proxy.MethodInterceptor;
* import org.springframework.cglib.proxy.MethodProxy;
*
* import java.lang.reflect.Method;
*
*/
public class DemoTest {
static class FooService {
public final void testMethod() {
System.out.println("FooService.testMethod action");
}
}
static class SimpleInterceptor implements MethodInterceptor {
/**
*
* @param proxy 代理
* @param method 要调用的方法
* @param args 方法参数
* @param methodProxy 方法代理
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("entering " + method.getDeclaringClass().getSimpleName() + "::" + method.getName());
//调用超类的方法:即调用被代理的类的方法
Object result = methodProxy.invokeSuper(proxy, args);
System.out.println("leaving " + method.getDeclaringClass().getSimpleName() + "::" + method.getName());
return result;
}
}
/**
*
* @param targetClass 目标类(被代理的类)
* @param <T> 目标类类型
* @return
*/
private static <T> T getProxy(Class<T> targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new SimpleInterceptor());
enhancer.setUseCache(true);
return (T) enhancer.create();
}
public static void main(String[] args) {
FooService proxy = getProxy(FooService.class);
proxy.testMethod();
}
}
cglib的实现机制与java不同,它是通过继承实现的,它也是动态创建了一个类,
但这个类的父类是被代理的类,代理类重写了父类的所有public非final方法,
并且目标类方法的调用改为调用Callback中的相关方法,如上述code,调用SimpleInterceptor的intercept方法。
cglib动态代理注意事项,被代理类中定义的final方法可以被调用
但是不会走代理逻辑
,因为final方法无法被子类(代理类)重写