译文
代理模式:为其他对象提供一种代理以控制这个对象的访问
代理模式的结构和uml类图
- 抽象主题(Subject)
- 实际主题(RealSubject)
- 代理(Proxy)
类图的解释
实际主题和主题的代理对象都实现抽象主题接口,同时主题的代理对象维护一个对实际主题的引用 这样的话用户就可以直接使用主题的代理对象完成业务逻辑 然后主题的代理对象在不改变主题的基础上可以对主题的进行控制
一个通俗易懂的例子
通俗理解就是主题和代理主题就是老板和小秘书,一般的电话都是小秘书接听的 小秘书自行判断是否需要让老板接电话 然后还可以在老板接听完电话之后帮助老板整理一下
uml类图
代码实现
public interface Human {
void healPhone();
}
public class Boss implements Human{
@Override
public void healPhone() {
System.out.println("我是老板 你干嘛啊");
}
}
public class Secretary implements Human{
private Boss boss;
public Secretary(Boss boss) {
this.boss = boss;
}
@Override
public void healPhone() {
System.out.println("我是秘书 我们先唠会嗑");
boss.healPhone();
System.out.println("可怜的秘书 开始整理材料");
}
}
public class Test {
public static void main(String[] args) {
Secretary secretary=new Secretary(new Boss());
secretary.healPhone();
}
}
基于jdk的代理
同样是上面的例子 我们用jdk提供的动态代理试试
在上面我们写了秘书类 但是这里我们就不用写这个类了
public class SecretaryFactory implements InvocationHandler {
private Human target;
public SecretaryFactory() {
target=new Boss();
}
Object getInstance(){ //返回一个主题的代理对象 就是秘书 因为jdk替我们实现了这个功能 我们就没必要写一个秘书类了
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是秘书 我们先唠会嗑");
Object invoke = method.invoke(target,args);
System.out.println("可怜的秘书 开始整理材料");
return invoke;
}
}
public class Test {
public static void main(String[] args) {
SecretaryFactory secretaryFactory =new SecretaryFactory();
Human instance = (Human) secretaryFactory.getInstance();
instance.healPhone();
}
}
简单的aop实现
- 创建一个maven工程
- 添加xml文件(自己定义的)
- 导包dom4j解析xml
- 编写简单的接口和实现类
- 编写进行增强的方法
- 编写代理类(基于jdk)
- 编写测试类
添加依赖
<dependencies>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
添加xml文件(自己定义的)
<?xml version="1.0" encoding="UTF-8"?>
<proxys>
<proxy id="MyProxy" class="com.yxx.CalcImp">
<method name="add">
<prefix bean="com.yxx.SendMessage" mtd="preAdd" />
<suffix bean="com.yxx.SendMessage" mtd="afterAdd" />
</method>
</proxy>
</proxys>
编写简单的接口和实现类
public interface Calc {
void add();
}
public class CalcImp implements Calc{
@Override
public void add() {
System.out.println("正在执行加法运算");
}
}
编写进行增强的方法
public class SendMessage{
public void preAdd() {
System.out.println("加法计算之前");
}
public void afterAdd() {
System.out.println("加法运算之后");
}
}
编写代理类(基于jdk)
package com.yxx;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Author: YuXinXin
* @Description:
* @Date:Created in 9:06 2020/12/31
**/
public class MyProxy implements InvocationHandler {
public Class target;
Element myProxy;
public Object getProxy(String id) {
try {
File f = new File("src/main/resources/1.xml");
Document doc = new SAXReader().read(f);
Element root = doc.getRootElement();//xml的根节点
for (Element element : root.elements()) {
if(element.attributeValue("id").equals(id)){ //找到用户需要的代理
myProxy= element;
String proxyClass=myProxy.attributeValue("class");
target=Class.forName(proxyClass); //获得类
}
}
} catch (Exception e) {
e.printStackTrace();
}
return Proxy.newProxyInstance(target.getClassLoader(),target.getInterfaces(),this);//创建代理对象
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Element myMethod = myProxy.elements().get(0);
String methodName=myMethod.attributeValue("name");
if(method.getName().equals(methodName)){
String bean1 = myMethod.elements().get(0).attributeValue("bean");
String mtd1 = myMethod.elements().get(0).attributeValue("mtd");
String bean2 = myMethod.elements().get(1).attributeValue("bean");
String mtd2 = myMethod.elements().get(1).attributeValue("mtd");
//方法开始前增强
Object obj1 = Class.forName(bean1).newInstance();
Method method1 = obj1.getClass().getDeclaredMethod(mtd1);
method1.invoke(obj1);
//执行方法
method.invoke(target.newInstance(),args);
//方法开始之后增强方法
Object obj2 = Class.forName(bean2).newInstance();
Method method2 = obj2.getClass().getDeclaredMethod(mtd2);
method2.invoke(obj2);
}
return null;
}
}
编写测试类
public class Text {
public static void main(String[] args) {
Calc calc=(Calc)new MyProxy().getProxy("MyProxy");
calc.add();
}
}