Java 代理模式

代理模式的定义

代理模式是为其他对象提供一种代理,使其可以控制对这个对象的访问,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 代理模式的优点,职责清晰,代理对象可以在客户端和目标对象起到中介的作用,代理对象保护了目标对象防止直接暴露给客户端,代理对象还可以扩展目标对象的功能

代理相关角色创建

创建抽象角色

1
2
3
4
5
6
7
8
9
/**
* @author WXY
* 抽象角色--接口
*/
public interface IUserDao {

void save();

}

创建代理的目标对象

1
2
3
4
5
6
7
8
9
10
11
/**
* @author WXY
* 接口实现--目标对象
*/
public class UserImpl implements IUserDao {

@Override
public void save() {
System.out.println("------------------user save---------------");
}
}

静态代理

静态代理需要实现抽象角色的接口,实现与目标对象相同的方法,再通过set方法注入目标对象,进而扩展目标对象的功能,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* @author WXY
* 代理对象--静态代理
*/
public class UserProxy implements IUserDao{

private IUserDao userDao;

public UserProxy(IUserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
System.out.println("-------------start-----------");
userDao.save();
System.out.println("---------------end--------------");
}
}

使用静态代理:

1
2
3
IUserDao userDao = new UserImpl();
UserProxy userProxy = new UserProxy(userDao);
userProxy.save();

静态代理需要代理类与被代理类要实现同一个接口,所以会出现大量的代码重复,每一种需要代理的对象都要实现不同的相对应的接口导致代码重用性低,使用繁琐。

JDK动态代理

JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象 以及 方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* @author WXY
* jdk-动态代理类
*/
public class ProxyFactory implements InvocationHandler {

private IUserDao userDao;

public Object getInstance(IUserDao userDao){
this.userDao = userDao;
Class clazz = userDao.getClass();
System.out.println("道理对象是"+clazz);
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-------------------------------");
System.out.println("jdk动态代理");
method.invoke(this.userDao,args);
System.out.println("--------------------------------");
return null;
}
}

jdk代理使用:

1
2
IUserDao user = (IUserDao) new ProxyFactory().getInstance(userDao);
user.save();

JDK的动态代理是通过接口来进行强制转换的,生成以后的代理对象,可以强制转换为接口,被代理对象必须实现该接口

CGLib动态代理

CGLIB是一个强大的、高性能的代码生成库 ,CGLIB代理是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。

引入cglib包

1
2
3
4
5
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>

cglib代理工厂类

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
/**
* cglib代理
* @author WXY
*/
public class CglibProxy implements MethodInterceptor {

/**
* 获取代理对象
* @param clazz 代理对象
* @return 代理后对象
*/
public static Object getInstance(Class clazz){
// 使用cglib代理
Enhancer enhancer = new Enhancer();
//继承的代理类
enhancer.setSuperclass(clazz);
//设置回调
enhancer.setCallback(new CglibProxy());
return enhancer.create();
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("-------------执行之前-----------"+method.getName());
//一定invokeSuper,调用invoke会出现死循环
Object object = methodProxy.invokeSuper(o,objects);
System.out.println("--------------执行之后-------"+method.getName());
return null;
}
}

代理使用:

1
2
IUserDao proxyUserDao = (IUserDao)CglibProxy.getInstance(UserImpl.class);
proxyUserDao.save();

CGLib的动态代理是通过生成一个被代理对象的子类,然后重写父类的方法,生成以后的对象,可以强制转换为被代理对象(也就是用自己写的类),子类引用赋值给父类