行为模式--代理Proxy模式(Java)
代理(AOP切面的雏形):
题记:顾名思义就是将某件事,某个东西的使用权进行为让授权转移。代理相当于中介(不同于中介者模式),在原本操作的类之间添加了一个桥梁。但代理不能去修改原有目标。比如:一个人要买 房,让中介帮忙给看个房,但中介不能将原有看房这件事变更为看车。他可以对看房提出各种要求和咨询。
回到程序的角度,调用者将调用某些共性类的处理交由代理类处理,代理类根据调用者的要求即满足什么情况可以调用,什么情况不能调用,(卖房者委托中介100万以上卖,100万以下不卖)对处理做前后的包装,但是代理类不能去改变被调用类的内部处理(可口可乐中国区可修改可口可乐包装,但不能在没授权情况下去更改可口可乐饮料)。
1.静态代理
2.动态代理
1.静态代理:对指定接口类做代理,通过对执行方法前后做处理,来实现代理的作用。因对指定接口类,因此可做某些特定类的特殊处理。
/**
* 静态代理,也被称为decate模式
*
* @author DennyZhao
* @date 2017年6月13日
* @version 1.0
*/
public class AnimalProxyFactory implements AnimalFactory {
/**
* 序列号
*/
private static final long serialVersionUID = -3421761900236678842L; private AnimalFactory animal; public AnimalProxyFactory(AnimalFactory animal){
this.animal = animal;
}
@Override
public int getLegs() {
System.out.println("before....action");
int legs = animal.getLegs();
System.out.println("after....action");
return legs;
} }
测试Main:
// 静态代理
Rabit rabit = new Rabit();
AnimalProxyFactory proxyFactory = new AnimalProxyFactory(rabit);
System.out.println(proxyFactory.getLegs());
运行结果:
>>>before....action
>>>after....action
>>>4
2.动态代理:动态代理通过Proxy类创建代理,通过InvokationHandler去调用方法。
package pattern.creation.factory; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Proxy;
import java.util.Properties; /**
* 动态代理模式
*
* @author DennyZhao
* @date 2017年6月13日
* @version 1.0
*/
public class ProxyFactory {
private static final String CLASS_NAME_PATH = "pattern/classname.properties";
@SuppressWarnings("unchecked")
public static <T> T getInstance(String name) throws IllegalArgumentException, InstantiationException, IllegalAccessException{
String className = getClassName(name);
T result = null;
try {
Class clazz = Class.forName(className);
result = (T)Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new MyInvocationHandler(clazz.newInstance()));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return result;
} /**
* 获取类名称
* @return
*/
private static String getClassName(String name) {
Properties pro = new Properties();
try {
String url = ProxyFactory.class.getClassLoader().getResource("").getPath() + CLASS_NAME_PATH;
pro.load(new FileInputStream(url));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return (String)pro.get(name);
}
}
注意* : 代理面向的是接口,因此委托的类都需要实现指定的接口。
result = (T)Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new MyInvocationHandler(clazz.newInstance()));
clazz.getInterfaces():如果一个clazz实现多个接口,此处要传入接口Class。
MyInvocationHandler 实现 InvocationHandler接口,里面要实现一个invoke方法,在这个invoke方法中填写处理。
// 可通过放射机制,来处理特殊类的特殊请求。
测试Main:
// 动态代理,AOP切面的雏形做法
AnimalFactory sheep = ProxyFactory.getInstance("sheep");
sheep.getLegs();
// 动态代理,AOP切面的做法
PlantFactory plum = ProxyFactory.getInstance("plum");
plum.getColor();
// 动态代理,AOP切面的做法
AnimalFactory rabit0 = ProxyFactory.getInstance("rabit");
rabit0.getLegs();
结果:
before-------
sheep has 4 legs....
after-------
before-------
plum green purple....
after-------
before-------
兔子是特殊的
after-------
深入理解静态代理和动态代理:
静态代理:需要代理类和实体类拥有同一个接口,这样才能保证口径一致,即代理商不能随意改变原实体类的行为。在代理类中将实体类注入进去,实现代理类和实体类的关联。这样在调用代理类时,会找到对应的实体类触发其行为,在调用前后又可以写入其它信息比如轨迹日志。
// 静态代理
IAnimal animal = new Sheep();
IAnimal proxy = new ProxyAnimal(animal);
System.out.println(proxy.getName());
jdk动态代理:动态代理的本质和静态代理是一致的。只不过动态代理是因为事前根本不知道要去代理谁,且原静态代理类,如果要实现代理需要写相同的实体类的相关接口,和好多代理类,扩展维护很麻烦。因此就采用一种动态代理。 通过定义一个类 实现 InvocationHandler接口的方法,即统一的代理行为,之后的所有代理信息都会进入到这个方法中,包括目标方法和目标参数。然后再由一个Proxy静态类,去在运行时创建一个类class $Proxy0,这个类会由ProxyGenerate根据传入的所有的接口,通过反射获取他们的方法,实现他们的方法,同时把Invocationhandler注入到这个类中,生成类似我们静态代理的临时类。坦白的说只是把我们自己写代理的这个过程交给机器来编写实现。
InvocationHandler invocation = new AnimalInvocation(new Sheep());
// 动态代理
Object animals = Proxy.newProxyInstance(invocation.getClass().getClassLoader(), new Class[]{IAnimal.class, IPlant.class}, invocation);
IPlant plant = (IPlant) animals;
IAnimal animal = (IAnimal) animals;
在这个 invocation中我们可以传入我们的实体对象(构造带参的构造器),也可以不传递通过rpc或者远端http请求获取Feign。
public class AnimalInvocation implements InvocationHandler {
private Object obj;
/**
* 创建代理对象
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(proxy.getClass());
// rcp调用远端接口处理数据,返回 method, obj ,args
return "其实我什么都不是";
//return method.invoke(obj, args);
}
spring有个AOP的切面使用的也是反向代理,只不过他的实现机理和我们JDK的内部的有些不一样。spring用的是cJlib,通过创建一个子类继承当前的service类。在调用中通过super来调用父类的方法实现代理。祥见 spring-AOP切面
因service中可以不定义接口,yi'ni'c
行为模式--代理Proxy模式(Java)的更多相关文章
- Java设计模式(10)代理模式(Proxy模式)
理解并使用设计模式,能够培养我们良好的面向对象编程习惯,同时在实际应用中,可以如鱼得水,享受游刃有余的乐趣. Proxy是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结构,P ...
- Proxy模式(代理[延迟]模式)
Proxy?? Proxy是"代理人"的意思,它指的是代替别人进行工作的人.代理实际上就是使用委托的机制,在代理的过程中你可以做点其他的事情,然后再来执行被代理对象的代码. 知识储 ...
- 代理(Proxy)模式简介
Proxy 模式简介 代理模式的两个应用: 打开文档时加载大图片 例如:如果有个对象是一张很大的图片,而这张图片需要花费很长时间才能显示出来,那么当这个图片包含在文档中的后面时,使用编辑器或浏览器打开 ...
- 十、设计模式之代理(Proxy)模式
什么是代理模式 代理模式是对象的结构模式,为其他对象提供一种对象以控制对这个对象的访问. 代理模式的结构图如下:(源自大话设计模式) Subject:定义了RealSubject和Proxy的公共 ...
- Java 实现代理(Proxy)模式
类图 /** * 游戏者接口 * @author stone * */ public interface IGamePlayer { // 登录游戏 public void login(String ...
- 代理(Proxy)模式
代理模式的类图如下所示: 客户端想调用的是RealSubject,由于某种考虑或原因,只能直接访问到ProxySubject,再由ProxySubject去调用RealSubject,这就完成了一次代 ...
- Android与设计模式——代理(Proxy)模式
在阎宏博士的<JAVA与模式>一书中开头是这样描写叙述代理(Proxy)模式的: 代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 代理模式 ...
- 漫谈设计模式(一):代理(Proxy)模式与适配器(Adapter)模式对比
1.前言 为什么要将代理模式与适配器模式放在一起来说呢?因为它们有许多的共同点,当然也有一些不同的地方.首先两者都是属于结构型模式.结构型模型是这样定义的: 结构型模式涉及到如何组合类和类以获得更大的 ...
- Head First 设计模式 —— 13. 代理 (Proxy) 模式
思考题 如何设计一个支持远程方法调用的系统?你要怎样才能让开发人员不用写太多代码?让远程调用看起来像本地调用一样,毫无瑕疵? P435 已经接触过 RPC 了,所以就很容易知道具体流程:客户端调用目标 ...
随机推荐
- 服务容错保护断路器Hystrix之三:断路器监控(Hystrix Dashboard)-单体监控
turbine:英 [ˈtɜ:baɪn] 美 [ˈtɜ:rbaɪn] n.汽轮机;涡轮机;透平机 一.Hystrix Dashboard简介 在微服务架构中为了保证程序的可用性,防止程序出错导致网络阻 ...
- asp.net控件拖不动。控件错误
有一种可能是工程的存储路径名称不规范导致,更改命名空间及路径. 我的存储路径是C#文件夹下,去掉#完美解决
- 廖雪峰Java2面向对象编程-4抽象类和接口-2接口
1.接口的定义 抽象方法本质上是定义接口规范. 在抽象类中定义了一个抽象方法,子类中必须实现这个抽象方法. public abstract class Person{ public abstract ...
- 解决hash冲突的三个方法(转)
https://www.cnblogs.com/wuchaodzxx/p/7396599.html 目录 开放定址法 线性探测再散列 二次探测再散列 伪随机探测再散列 再哈希法 链地址法 建立公共溢出 ...
- 使用SHOW binlog events查看binlog内容
用mysqlbinlog命令行查看binlog,觉得比较麻烦,突然发现原来mysql有个命令可以直接查看. SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] ...
- 详解http和https的作用与区别
PS: https就是http和TCP之间有一层SSL层,这一层的实际作用是防止钓鱼和加密.防止钓鱼通过网站的证书,网站必须有CA证书,证书类似于一个解密的签名.另外是加密,加密需要一个密钥交换算法, ...
- MyBatis配置Mapping,JavaType和JDBCType的对应关系,#与$区别
Mybatis中javaType和jdbcType对应关系:JDBC Type Java TypeCHAR StringVARCHAR StringLONGVARCHAR StringNUMERIC ...
- 您无法登陆系统。原因可能是您的用户记录或所属的业务部门在Microoft Dynamics CRM中已被禁用
问题发生在CRM 4.0 上 1 用户所在办事处及办事处上级被禁用. 2 如果已经重新启用了,还是报这个错误. 可以把停用的办事处及相关下级再重新--停用--启用一次试试. 3 如果还是报错,查看是否 ...
- JPA查询
Pojo: UserDetails EntityManager: entityManager 1. Ceate Criteria CriteriaBuilder builder = entityMan ...
- TP微信扫码支付
1.官网下载php扫码支付adk,放在项目引入第三方类库中 2.配置config中相关参数 注意:可能会遇到问题 微信支付错误问题的解决:curl出错,错误码:60 Fatal error: Unca ...