什么是代理?
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法
举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决.这就是代理思想在现实中的一个例子
java中的代理类型
静态代理
-
代理对象和目标对象(委托对象)都要实现相同的接口;
-
当有很多目标需要被代理时,需要手动写很多代理类,会造成代码重复和膨胀;
动态代理
-
目标对象需要实现接口,代理对象不需要实现接口;
-
能在运行时自动生成代理对象,不需要手动写很多代理类,不会有代码重复和膨胀;
demo
java
package delegate.jdk;
public interface IHello {
String hello(String name);
}
java
package delegate.jdk;
public class HelloImpl implements IHello {
@Override
public String hello(String name) {
return "Hello, " + name;
}
}
java
package delegate.jdk;
import java.lang.reflect.Proxy;
public class RuntimeProxyFactory {
public static Object createProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
long startTimeStamp = System.currentTimeMillis();
Object returnValue = method.invoke(target, args);
long endTimeStamp = System.currentTimeMillis();
long runtime = endTimeStamp - startTimeStamp;
System.out.println("Runtime: " + runtime);
return returnValue;
}
);
}
}
java
package delegate.jdk;
public class ProxyTest {
public static void main(String[] args) {
IHello hello = (IHello) RuntimeProxyFactory.createProxy(new HelloImpl());
System.out.println(hello.hello("Lee"));
}
}
原理分析(todo)
cglib代理
- 目标类也不需要实现接口;(代理类继承目标类,以目标类子类的方式实现代理,所以也叫子类代理,因为是基于继承实现,所以目标类及其方法不能被final修饰)
demo
java
package delegate.cglib;
public class Hello {
public String hello(String name) {
return "Hello, " + name;
}
}
java
package delegate.cglib;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class RuntimeInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
long startTimeStamp = System.currentTimeMillis();
Object returnValue = methodProxy.invokeSuper(o, objects);
long endTimeStamp = System.currentTimeMillis();
long runtime = endTimeStamp - startTimeStamp;
System.out.println("Runtime: " + runtime);
return returnValue;
}
}
java
package delegate.cglib;
import org.springframework.cglib.proxy.Enhancer;
public class RuntimeProxyFactory {
public static Object createProxy(Object target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new RuntimeInterceptor());
return enhancer.create();
}
}
java
package delegate.cglib;
public class ProxyTest {
public static void main(String[] args) {
Hello hello = (Hello) RuntimeProxyFactory.createProxy(new Hello());
System.out.println(hello.hello("Lee"));
}
}
原理分析(todo)
Spring AOP中的动态代理
在Spring的AOP编程中:如果加入容器的目标对象有实现接口,用JDK代理;如果目标对象没有实现接口,用Cglib代理。