代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。
在这里给一个举例说明一下:
租客向要去找一个房间租用,虽然它可以自己去找房源源,但是这样太慢且太费时,所以大多数租客都会选择找中介或者是租房公司去帮忙找满足自己要求的房源。这个过程就是代理模式。本应该租客们处理的shiq交予租房公司解决。
静态代理:由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
/**
* @description: 人-父类
* @author: lichunkai
* @create: 2019-11-21 00:02
**/
public interface Person {
//所有人都需要住所
void needHouse();
}
/**
* @description: 学生
* @author: lichunkai
* @create: 2019-11-20 23:55
**/
public class Student implements Person {
@Override
public void needHouse() {
//要求
System.out.println("我是学生:我需要一个学区房,离学校要近");
}
}
**
* @description: 码农
* @author: lichunkai
* @create: 2019-11-21 00:18
**/
public class Coder implements Person{
@Override
public void needHouse() {
System.out.println("我是码农:我的要求是房租便宜,我没有钱");
}
}
/**
* @description: 中介
* @author: lichunkai
* @create: 2019-11-20 23:58
**/
public class Agent implements Person{
private Person person ;
public Agent(Person person){
this.person = person;
}
@Override
public void needHouse() {
//中介了解客户的要求
System.out.println("你的要求是什么");
person.needHouse();
//根据客户要求找房子
if(person.getClass() == Coder.class){
System.out.println("根据你的要求我会为你找便宜的房子");
}else if(person.getClass() == Student.class){
System.out.println("根据你的要求我会为你找学区房");
}
}
}
/**
* @description: 测试类
* @author: lichunkai
* @create: 2019-11-21 00:23
**/
public class Test {
public static void main(String[] args) {
System.out.println("--------------码农找房----------");
//程序员找房
Agent agent1 = new Agent(new Coder());
agent1.needHouse();
System.out.println("--------------学生找房----------");
//学生找房
Agent agent2 = new Agent(new Student());
agent2.needHouse();
}
}
代理类在程序运行时创建的代理方式被成为动态代理。 我们上面静态代理的例子中,代理类(studentProxy)是自己定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。【其实就是通过反射调用,这样可很方便的对代理类的函数进行统一的处理。】
该种代理模式的实现需要实现jdk接口InvocationHandler ,并且通过Proxy类产生的代理对象
/**
* @program: prepare02
* @description: 人-父类
* @author: lichunkai
* @create: 2019-11-21 00:02
**/
public interface JDKPerson {
//所有人都需要住所
void needHouse();
}
/**
* @program: prepare02
* @description: 实体-学生
* @author: lichunkai
* @create: 2019-11-20 23:55
**/
public class JDKStudent implements JDKPerson {
@Override
public void needHouse() {
//要求
System.out.println("我是学生:我需要一个学区房,离学校要近");
}
}
/**
* @program: prepare02
* @description: 码农
* @author: lichunkai
* @create: 2019-11-21 00:18
**/
public class JDKCoder implements JDKPerson{
@Override
public void needHouse() {
System.out.println("我是码农:我的要求是房租便宜,我没有钱");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @program: prepare02
* @description: 中介
* @author: lichunkai
* @create: 2019-11-20 23:58
**/
public class AgentJDKProxy implements InvocationHandler {
// 目标类
private JDKPerson target;
public Object getInstance(JDKPerson target){
this.target = target;
Class<?> clazz = target.getClass();
// 通过反射生产目标对象(字节码重组来实现 新的对象 Proxy)
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
/**
* 执行目标类目标方法
* @param proxy 代理对象
* @param method 目标方法(代表正在执行的方法)
* @param args 目标方法的参数(代表正在执行的方法的实参)
* @return 表示当前执行方法的返回值
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 可以进行定制开发
System.out.println("调用的目标方法:" + method.getName());
System.out.println("我是jdk中的中介: 我要给你找房子");
// 执行目标方法 反射
method.invoke(this.target, args);
// 可以进行定制开发
System.out.println("正在根据你的要求找房子中。。。");
return null;
}
}
/**
* @program: prepare02
* @description: 测试Jdk动态代理
* @author: lichunkai
* @create: 2019-11-21 01:02
**/
public class JDKTest {
public static void main(String[] args) {
System.out.println("----------码农找房-------");
JDKPerson obj1 = (JDKPerson) new AgentJDKProxy().getInstance(new JDKCoder());
System.out.println(obj1.getClass());
obj1.needHouse();//调用该方方法时,会先调用AgentJDKProxy.invoke() 通过反射获取方法
System.out.println("----------学生找房-------");
JDKPerson obj2 = (JDKPerson) new AgentJDKProxy().getInstance(new JDKStudent());
System.out.println(obj2.getClass());
obj2.needHouse();//调用该方方法时,会先调用AgentJDKProxy.invoke() 通过反射获取方法
}
}
cglib代理模式是第三方提供的一种方式,所以需要导入相应的包。当然因为第三方的原因,他的功能会比jdk代理模式更加强大。【性能上jdk和cglib两者是一样的】
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
/**
* @description: 男人
* @author: lichunkai
* @create: 2019-11-21 13:00
**/
public class Man {
//说明情况 并且返回需求
public String getLove() {
System.out.println("我是男人,我要找个女朋友");
return "我要找个女朋友";
}
}
/**
* @description: 女人
* @author: lichunkai
* @create: 2019-11-21 13:00
**/
public class Woman {
//说明情况 并且返回需求
public String getLove() {
System.out.println("我是女人,我要找个男朋友");
return "我要找个男朋友";
}
}
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @description: cgllib代理类-这里表示为媒婆
* @author: lichunkai
* @create: 2019-11-21 13:12
**/
public class CglibProxy implements MethodInterceptor {
// 目标类
public Object getInstance(Class<?> clazz){
// 代理类创建
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("我是媒婆获取到了你的要求了");
//invokeSuper不仅会运行一遍还会返回原有的返回值
//这是我们就可以统一更改返回值了
Object repose = methodProxy.invokeSuper(o, objects);
System.out.println("我会处理的");
repose = "我进入了返回值:"+repose.toString();
return repose;
}
}
/**
* @description: 测试
* @author: lichunkai
* @create: 2019-11-21 13:22
**/
public class PoxyTest {
public static void main(String[] args) {
Man obj = (Man) new CglibProxy().getInstance(Man.class);
System.out.println(obj.getClass());
String reponse = obj.getLove();
System.out.println("----返回值已经被更改: "+reponse);
System.out.println("----------Woman------------");
Woman obj2 = (Woman) new CglibProxy().getInstance(Woman.class);
System.out.println(obj2.getClass());
String reponse2 = obj2.getLove();
System.out.println("----返回值已经被更改: "+reponse2);
}
}