代理,是一种设计模式,提供了对目标对象的一种访问方式,即通过代理访问目标对象。
代理,从实现方式来分,可以分为两大类:静态代理和动态代理。动态代理根据实现的方式,可以分为:jdk动态实现和cglib动态实现。
一、静态代理
实现一个对象的静态代理,需要该对象继承一个接口,同时代理类也继承该接口。主要包括三个部分组成:
- 代理目标接口:代理类和目标实现类的基本模板,代理类和目标类都需要实现接口方法。
- 目标对象:实现代理目标接口的实现类。
- 代理类:持有目标对象,根据不同策略选择不同的方法调用目标对象的方法。
优缺点:
优点:做到不修改目标对象功能代码的前提下,对目标功能进行扩展,这也是代理模式的最终目的。
缺点:因为代理类和目标类实现同样的接口,如果修改接口,很多代理类和实现类都要维护,不解耦。
下面写个简单的静态代理类的实现
代理目标接口:
public interface Person {
void say();
}
两个实现类:Doctor和Police
public class Doctor implements Person{
@Override
public void say() {
System.out.println("my job is Doctor!");
}
}
public class Police implements Person{
@Override
public void say() {
System.out.println("my job is police!");
}
}
代理类,没有修改实现类Person和Doctor任何代码,实现了新增功能,比如打印事件戳。
public class PersonProxy implements Person{
Person police = new Police();
Person doctor = new Doctor();
@Override
public void say() {
}
public void whoSay(String jobName){
System.out.println(System.currentTimeMillis());
if (jobName.equals("police")){
police.say();
} else if (jobName.equals("doctor")){
doctor.say();
} else {
System.out.println("输入的职业名称暂未录入系统!");
}
}
public static void main(String[] args){
PersonProxy proxy = new PersonProxy();
proxy.whoSay("doctor");
proxy.whoSay("mabi");
}
}
二、JDK动态代理
JDK主要使用Java.lang.reflect包中的反射逻辑来实现类的动态代理生成。可根据具体的实现类,动态生成代理。
由一下四个部分组成:
- 目标类接口
- 目标实现类
- Java.lang.reflect.Proxy类的Object new ProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h),生成动态代理。
- InvocationHandler接口的实现类:实现调用目标类的扩展逻辑。
优缺点:
优点:代理通用的有点,不改变实现类,扩展了功能。
缺点:必须实现接口,不然无法实现动态代理。
实现代码样例
代理目标接口
public interface Person {
void say(String word);
}
两个实现类,Doctor和Police
public class Doctor implements Person{
@Override
public void say(String word) {
System.out.println("我是医生,"+word);
}
}
public class Police implements Person{
@Override
public void say(String word) {
System.out.println("我是警察,"+word);
}
}
InvocationHandler接口的实现类,即代理新增功能处理类
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;
public ProxyInvocationHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(System.currentTimeMillis());
Object resultValue = method.invoke(target,args);
System.out.println("finish: "+System.currentTimeMillis());
return resultValue;
}
}
main方法测试代理调用
public class MyTest {
public static void main(String[] args){
Person doctor = new Doctor();
Person police = new Police();
//doctor代理处理逻辑
InvocationHandler doctorHandler = new ProxyInvocationHandler(doctor);
//police代理处理逻辑
InvocationHandler policeHandler = new ProxyInvocationHandler(police);
//生成doctor代理
Person doctorProxy = (Person) Proxy.newProxyInstance(doctor.getClass().getClassLoader(), doctor.getClass().getInterfaces(),doctorHandler);
//生成police代理
Person policeProxy = (Person) Proxy.newProxyInstance(police.getClass().getClassLoader(), police.getClass().getInterfaces(),policeHandler);
doctorProxy.say("为人民服务");
policeProxy.say("为人民服务");
}
}
三、Cglib实现代理
Cglib不需要实现类有统一的接口,实现方式其实和jdk的动态代理类似,可以理解cglib方式生成的是目标类的子类,通过子类来增强了目标类的功能。
需要以下三个部分:
- 目标实现类:具体逻辑
- 代理类:实现MethodInterceptor接口,是代理新增功能的实现
- Enhancer:设置代理类,并生成代理对象
实现样例代码:
public class MyDemo {
public static void main(String[] args){
LinkManDao linkManDao = new LinkManDao();
//创建cglib核心对象
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(linkManDao.getClass());
//设置回调
enhancer.setCallback(new 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("开始存储联系人");
Object result = method.invoke(linkManDao,args);
System.out.println("存储联系人结束");
return result;
}
});
//创建代理对象
LinkManDao proxy = (LinkManDao) enhancer.create();
proxy.save();
}
}