静态代理和动态代理

什么是代理

代理是为其它对象提供一种代理以控制这个对象的访问,Java中的代理分为下面三种角色:

  1. Subject(抽象角色): 通过接口或抽象类声明真实角色实现的业务方法。

  2. RealSubject(目标角色): 实现抽象角色,定义目标角色所要实现的业务逻辑,供代理角色调用。

  3. Proxy(代理角色): 实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。

代理模式根据生成代理类时机的不同分为两种,分为静态代理动态代理,静态代理在编译期就已经生成代理类,动态代理是在程序运行的时候动态生成代理类。

静态代理

静态代理要求委托类(RealSubject)和代理角色(Proxy)必须实现同一个接口或者继承同一个父类,否则无法生成代理类。

抽象角色

1
2
3
public interface Action {
void doSomething();
}

目标角色

1
2
3
4
5
6
public class RealObject implements Action {
@Override
public void doSomething() {
System.out.println("do something");
}
}

代理角色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ProxyObject implements Action {
private Action realObject;

public ProxyObject(Action realObject) {
this.realObject = realObject;
}

@Override
public void doSomething() {
// 自定义代理类的逻辑
System.out.println("proxy do");
// 调用被代理类的方法
realObject.doSomething();
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
public class StaticProxyTest {
public static void main(String[] args) {
// 被代理对象
Action realObject = new RealObject();
// 代理对象
Action proxyObject = new ProxyObject(realObject);

proxyObject.doSomething();

}
}

运行结果

1
2
proxy do
do something

动态代理

动态代理相比静态代理来说,它在一定程度上减少了代码冗余,它通过反射机制来创建代理类。它不要求委托类和代理类必须实现同一个接口或者继承同一个父类,但是委托类需要实现接口,代理类需要实现InvocationHandler接口。JDK动态代理主要涉及到两个类:java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler。比如说我们要代理同一个接口的不同实现,如果使用静态代理,我们就要生成多个代理类,而使用动态代理我们只需要一个代理类。

JDK动态代理

抽象角色
1
2
3
4
5
public interface UserDao {
void save();

Integer count();
}
目标角色
1
2
3
4
5
6
7
8
9
10
11
12
13
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("----已经保存数据!----");
}

@Override
public Integer count() {
Integer randomNum = new Random().nextInt(10000);
System.out.println("方法正在执行 - totalNum = " + randomNum);
return randomNum;
}
}
代理角色
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class JdkProxy implements InvocationHandler {
/**
* 需要代理的目标对象
*/
private Object targetObject;

public JdkProxy(Object targetObject) {
this.targetObject = targetObject;
}

public Object newProxy(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();

// 调用被代理对象的方法
Object returnValue = method.invoke(targetObject, args);

after();
return returnValue;
}

private void after() {
System.out.println("方法执行后");
}

private void before() {
System.out.println("方法执行前");
}
}
测试类
1
2
3
4
5
6
7
8
public class JdkDynamicProxyTest {

public static void main(String[] args) {
UserDao target = new UserDaoImpl();
UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance();
proxy.save();
}
}
运行结果
1
2
3
方法执行前
----已经保存数据!----
方法执行后

CGLIB动态代理

Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口。它通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑,来完成动态代理的实现。它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的拦截。使用CGLIB需要引入如下jar包。CGLIB代理方式不要求委托类必须实现接口或者继承一个父类,它通过继承委托类来实现代理,所以这也是它的一个缺点,它不能代理被final修饰的类

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm-all</artifactId>
<version>3.3</version>
</dependency>

目标角色

1
2
3
4
5
6
public class CglibDelegateClass {
public String test() {
System.out.println("我是委托类");
return UUID.randomUUID().toString();
}
}

代理角色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class CglibProxyClass implements MethodInterceptor {
private Object object;

public CglibProxyClass(Object o) {
this.object = o;
}

public Object getProxy(){
//1.工具类
Enhancer enhancer = new Enhancer();
//2.设置父类
enhancer.setSuperclass(object.getClass());
//3.设置回调函数
enhancer.setCallback(this);
//4.创建子类(代理对象)
Object object = enhancer.create();
return object;
}

public void before() {
System.out.println("before");
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object object = methodProxy.invokeSuper(o, objects);
after();
return object;
}

public void after() {
System.out.println("after");
}
}

测试类

1
2
3
4
5
6
public class CglibTest {
public static void main(String[] args) {
CglibDelegateClass cglibDelegateClass = (CglibDelegateClass) new CglibProxyClass(new CglibDelegateClass()).getProxy();
cglibDelegateClass.test();
}
}

运行结果

1
2
3
before
我是委托类
after

参考

  1. Java中的静态代理和动态代理
  2. 设计模式之代理模式(Proxy Pattern)
显示评论