什么是代理
代理:代理对象主要用来拦截目标业务对象(被代理对象)的访问。
A:代理对象要持有真实业务对象。(通过构造函数接收业务对象,并用成员变量记录)
B:代理对象要和真实业务对象,具备相同的行为方法(实现相同接口)
C:代理对象拦截对真实对象的访问,可以修改访问的参数、返回值,甚至拦截访问
代理模式与装饰模式区别
A:代理模式侧重与拦截,装饰模式侧重与加强
B:Java中自带的代理中,只能对接口进行代理。装饰只需要与被装饰类有共同父类。
举个栗子
定义person接口:
public interface Person {
public void buyMac(double money);
public void takeSubWay(double money);
public void atHome();
}
实现类Student:
public class Student implements Person {
@Override
public void buyMac(double money) {
System.out.println("学生买了个mac!");
System.out.println("学生花了" + money + "RMB");
}
@Override
public void takeSubWay(double money) {
System.out.println("学生乘坐地铁!");
System.out.println("学生了" + money + "RMB");
}
@Override
public void atHome() {
System.out.println("学生到家了好好休息");
}
}
写一个代理类HuangSir:
代理类同时实现person接口,持有业务对象Student,构造函数添加Student。重写Student中的方法。
public class HuangSir implements Person {
// 持有真实业务对象
private Student student;
// 接收真实业务对象
public HuangSir(Student student) {
this.student = student;
}
@Override
public void buyMac(double money) {
// 做一个拦截
if (money < 5000) {
System.out.println("没钱了,买不起!");
return;
}
System.out.println("使用学生卡,优惠了" + money * 0.1 + "元");
student.buyMac(money * 0.9);
}
@Override
public void takeSubWay(double money) {
// 做一个拦截
if (money < 50) {
System.out.println("没钱了,做不起地铁!");
return;
}
student.takeSubWay(money);
}
@Override
public void atHome() {
System.out.println("到了楼下!");
student.atHome();
}
}
测试类:
public static void main(String[] args) {
DynamicProxy2 dynamicProxy2 = new DynamicProxy2();
Person p = (Person)dynamicProxy2.getDynamicProxy();
// 访问方法
p.buyMac(5000);
System.out.println("---华丽的分界线---");
p.takeSubWay(10);
System.out.println("---华丽的分界线---");
p.atHome();
}
什么是动态代理
动态代理利用Java的反射技术,在运行时创建一个实现某些给定接口的代理类其实例,代理的对象是接口;
动态代理的作用:
1、可以解决特定问题:一个接口的实现在编译时无法知道,需要在运行时才能实现;
2、实现某些设计模式:适配器或修饰器;
3、面向切面编程:SpringAOP
动态代理在程序运行过程中产生的一个代理对象;
在程序运行的过程中,动态在内存中生成一个类,代理需要被代理的目标对象,并且生成这个代理类的对象。
public static void main(String[] args) {
// 创建被代理对象
final Student s = new Student();
// 先准备动态代理的三大参数
// 被代理类的类加载器
ClassLoader loader = s.getClass().getClassLoader();
// 被代理对象的接口的Class对象数组
Class<?>[] interfaces = s.getClass().getInterfaces();
// 调用处理器
InvocationHandler h = new InvocationHandler(){
// 当我们调用代理对象的功能时,代理对象,其实都来调用了处理器中的invoke功能
// 因此,我们需要在invoke中写拦截的逻辑!
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Object proxy : 是代理对象本身
// Method method :当前正在被调用的真实方法的对象
// Object[] args : 当前正在被调用的真实方法的真实参数
String name = method.getName();
// 判断方法的名称,做出不同的拦截逻辑
if( "buyMac".equals(name)){
double money = (double) args[0];
if (money < 5000) {
System.out.println("没钱了,买不起!");
return null;
}
System.out.println("使用学生卡,优惠了" + money * 0.1 + "元")
return method.invoke(s, money * 0.9);
}
if( "takeSubWay".equals(name)){
double money = (double) args[0];
if (money < 50) {
System.out.println("没钱了,做不起地铁!");
return null;
}
}
return method.invoke(s, args);
}
};
Person p = (Person) Proxy.newProxyInstance(loader, interfaces, h);
// 访问方法
p.buyMac(5000);
System.out.println("---华丽的分界线---");
p.takeSubWay(10);
System.out.println("---华丽的分界线---");
p.atHome();
}
返回结果同上