代理模式分两种:静态代理和动态代理
就是通过代理对象去控制对真实对象的访问
代理模式的作用: 可以通过代理对象去控制真实对象中的方法,代理对象就可以具备调用真实对象的所有方法的调用控制权
这样我们就可以在调用方法之前做一些前置处理,之后做一些后置处理
动态代理:可以在不修改源码的基础上动态地加入代码
静态代理
先看下面一段示例代码:
public class StaticProxyDemo {
public static void main(String[] args) {
// 创建真实对象
IStar ldh = new LdhStar();//刘德华
IStar zbz = new ZbzStart();//张柏芝
// 创建静态代理对象,只需要修改构造方法的ProxyManager的形参就能实现不同艺人的转换
ProxyManager proxy = new ProxyManager(zbz);
proxy.confer();
proxy.signContact();
proxy.bookTicket();
proxy.sing();
proxy.collectMoney();
}
}
// 公共接口: 真实对象和代理对象都能够实现的方法
interface IStar {
void confer();
void signContact();
void bookTicket();
void sing();
void collectMoney();
}
// 真实对象
class LdhStar implements IStar {
@Override
public void confer() {
System.out.println("刘德华面谈");
}
@Override
public void signContact() {
System.out.println("刘德华签合同");
}
@Override
public void bookTicket() {
System.out.println("刘德华订机票");
}
@Override
public void sing() {
System.out.println("刘德华唱歌");
}
@Override
public void collectMoney() {
System.out.println("刘德华收钱");
}
}
class ZbzStart implements IStar {
@Override
public void confer() {
System.out.println("张柏芝面谈");
}
@Override
public void signContact() {
System.out.println("张柏芝签合同");
}
@Override
public void bookTicket() {
System.out.println("张柏芝订票");
}
@Override
public void sing() {
System.out.println("张柏芝唱歌");
}
@Override
public void collectMoney() {
System.out.println("张柏芝收钱");
}
}
// 静态代理类
class ProxyManager implements IStar {
// 真实对象的引用
private IStar star;
public ProxyManager() {
super();
}
public ProxyManager(IStar star) {
super();
this.setStar(star);
}
@Override
public void confer() {
System.out.println("经纪人面谈");
}
@Override
public void signContact() {
System.out.println("经纪人签合同");
}
@Override
public void bookTicket() {
System.out.println("经纪人订票");
}
@Override
public void sing() {
star.sing();
}
@Override
public void collectMoney() {
System.out.println("经纪人收钱");
}
public IStar getStar() {
return star;
}
public void setStar(IStar star) {
this.star = star;
}
}
以上代码,可以通过修改形参,不该源码的形式实现对不同对象的操作,但是无法动态的增加代码,这样就需要使用动态代理
动态代理
动态代理的本质就是在代理对象方法调用之前或者之后加入一些通用的方法
面向切面编程就是代理模式的应用,也是AOP的基础
面向切面编程是面向对象的一种方式,在代码的执行过程当中,动态嵌入其他代码,成为面向切面编程
常见的应用场景:
- 日志
- 事物
- 数据库操作
面向切面编程的几个概念:
AOP本质就是动态代理
4. 切点(PointCut): 要对哪些连接点进行拦截的定义,即要添加代码的地方 例如info作为切点
5. 连接点(JointPoint): 类里面可以被增强的方法,这些方法称为连接点 (例如: info run add 三个连接点)
6. 增强(通知)(Advice): 指的是拦截到JoinPoint之后所要做的事情就是通知,即向切点插入的代码片段称为通知
通知的分类: 前置通知,后置通知,异常通知,最终通知,环绕通知
7. 目标对象(Target): 代理的目标对象,这里就是target
8. 织入(Weaving): 是把增强应用到目标的过程,即Advice应用到Target的过程
9. 代理(Proxy): 一个类被AOP织入增强后,就会产生一个结果代理类
10. 引介: 引介是一种特殊的通知在不修改源代码的前提下,可以在运行时期为类动态地加入一些方法或者字段
示例代码:
public class DynamicProxyDemo {
public static void main(String[] args) {
test1();
System.out.println("=============");
test2();
}
// 使用动态代理之前的做法
public static void test1() {
IDog dog = new GunDog();
DogUtils.method1();
dog.info();
DogUtils.method2();
DogUtils.method1();
dog.run();
DogUtils.method2();
}
// 代理之后的做法
public static void test2() {
IDog dog = new GunDog();
IDog proxy = (IDog) MyProxyFactory.getProxy(dog);
proxy.info();
proxy.run();
int result = proxy.add(10, 20);
System.out.println("result: " + result);
}
}
// 代理工厂
class MyProxyFactory {
public static Object getProxy(Object target) {
MyInvocationHandler handler = new MyInvocationHandler();
handler.setTarget(target);
// 通过真实对象实现的接口反推代理对象实现的接口
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), handler);
return proxy;
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
/**
* proxy: 代理对象
* method: 方法对象,具体调用了哪个方法,就会将这个方法对象传递给我们
* args: 调用者调用的方法的参数也会传递给我们
*
* 代理对象调用任何一个方法,都会让invoke方法被回调
* 并且将调用的方法对象传递给method,将方法的参数传递给args
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName(); // info
Object result = null;
switch (methodName) {
case "info":
DogUtils.method1();
method.invoke(target, args);
DogUtils.method2();
break;
case "run":
DogUtils.method1();
method.invoke(target, args);
DogUtils.method2();
break;
case "add":
result = method.invoke(target, args);
if (args != null) {
for (Object obj : args) {
System.out.println("args: " + obj);
}
}
break;
default:
break;
}
// 如果一个方法的返回值为void,这里返回void,如果返回值不为void,就返回对应结果
return result;
}
}
// 创建一个公共接口
interface IDog {
void info();
void run();
int add(int a, int b);
}
// 猎狗
class GunDog implements IDog {
@Override
public void info() {
System.out.println("一只猎狗");
}
@Override
public void run() {
System.out.println("猎狗在跑");
}
@Override
public int add(int a, int b) {
return a + b;
}
}
class DogUtils {
public static void method1() {
System.out.println("========通用方法一=========");
}
public static void method2() {
System.out.println("========通用方法二=========");
}
}