代理模式定义
代理模式(proxy pattern)指为对象提供一层代理,以控制对象的访问,属于结构型设计模式。
当无法或不想直接引用某个对象或访问某个对象困难时,可以通过代理对象来间接访问。使用代理模式主要有两个目的:1.保护目标对象 2.增强目标对象。
通用实现(写法)
public interface ISubject {
public void invokeMethod();
}
public class Subject implements ISubject{
@Override
public void invokeMethod() {
System.out.println("Subject invokeMethod");
}
}
//代理类
public class ProxySubject implements ISubject{
private ISubject iSubject;
ProxySubject(ISubject iSubject) {
this.iSubject = iSubject;
}
@Override
public void invokeMethod() {
before();
iSubject.invokeMethod();
after();
}
private void before(){
System.out.println("before");
}
private void after(){
System.out.println("after");
}
}
uml:
测试:
@Test
public void test(){
ProxySubject proxySubject = new ProxySubject(new Subject());
proxySubject.invokeMethod();
}
代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类
上述写法是静态代理,下面介绍动态代理
Jdk动态代理
上述的ProxySubject是代理类,我们需要实现Isubject接口,并手动创建该代理对象,调用目标方法。
而在动态代理中,我们可以让程序在运行的时候自动在内存中创建一个实现 Isubject接口的代理,而不需要去定义 ProxySubject这个类。
目前普遍使用的是Jdk动态代理和Cglib动态代理。现介绍Jdk动态代理。
两种写法:
实现InvocationHandler接口
public interface IJdkSubject {
public void invokeMethod();
}
public class JdkSubject implements IJdkSubject{
@Override
public void invokeMethod() {
System.out.println("JdkSubject invokeMethod");
}
}
public class JdkProxySubject1 implements InvocationHandler {
private IJdkSubject jdkSubject;
/**
* 创建代理对象
*/
public IJdkSubject createProxy(IJdkSubject jdkSubject){
this.jdkSubject = jdkSubject;
return (IJdkSubject)Proxy.newProxyInstance(jdkSubject.getClass().getClassLoader(), jdkSubject.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object invoke = method.invoke(jdkSubject, args);
System.out.println("after");
return invoke;
}
}
实现匿名内部类
public class JdkProxySubject2 {
public IJdkSubject createProxy(IJdkSubject jdkSubject){
return (IJdkSubject)Proxy.newProxyInstance(jdkSubject.getClass().getClassLoader(), jdkSubject.getClass().getInterfaces(), (proxy, method, args) -> {
System.out.println("before");
Object invoke = method.invoke(jdkSubject, args);
System.out.println("after");
return invoke;
});
}
}
测试:
@Test
public void test(){
JdkProxySubject1 jdkProxySubject1 = new JdkProxySubject1();
IJdkSubject proxy = jdkProxySubject1.createProxy(new JdkSubject());
proxy.invokeMethod();
}
@Test
public void test2(){
JdkProxySubject2 jdkProxySubject2 = new JdkProxySubject2();
IJdkSubject proxy = jdkProxySubject2.createProxy(new JdkSubject());
proxy.invokeMethod();
}
两种方法本质是一种,都是创建动态代理对象执行目标方法,都会进入InvocationHandler的invoke回调方法,通过此方法,可以对目标方法进行增强。
对于jdk动态代理来说,我们需要被代理类实现接口,那么没有实现接口的类就不能使用jdk动态代理了。由此引入cglib动态代理。
Cglib动态代理
导入相关jar包(在spring-core自带cglib可直接测试,或者导入其他cglib依赖包)
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
class CglibSubject {
void methodInvoke(){
System.out.println("CglibSubject methodInvoke");
}
}
public class CglibProxySubject implements MethodInterceptor {
CglibSubject createProxy(Class<CglibSubject> clazz){
//创建核心类,让它帮助我们创建代理对象
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(clazz);
//设置回调
enhancer.setCallback(this);
//创建代理
return (CglibSubject)enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before");
Object invoke = proxy.invokeSuper(obj, args);
System.out.println("after");
return invoke;
}
}
MethodInterceptor接口:
测试:
public class CglibTest {
@Test
public void test(){
CglibProxySubject cglibProxySubject = new CglibProxySubject();
CglibSubject proxy = cglibProxySubject.createProxy(CglibSubject.class);
proxy.methodInvoke();
}
}
我们发现:cglib动态代理的目标对象不需要实现任何接口,它是通过动态继承目标对象实现动态代理的