代理模式 
        代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

按照代理的创建时期,代理类可以分为两种:
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。

在JDK 1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例。 JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。

一、静态代理
1. 接口类:Count.java

public interface Count {
// 查看账户方法
public void queryCount();
// 修改账户方法
public void updateCount();
}

2. 实现类:CountImpl.java

public class CountImpl implements Count {
@Override
public void queryCount() {
System.out.println("查看账户方法...");
} @Override
public void updateCount() {
System.out.println("修改账户方法...");
}
}

3. 代理类:CountProxy.java

public class CountProxy implements Count {
private CountImpl countImpl; /**
* 覆盖默认构造器
* @param countImpl
*/
public CountProxy(CountImpl countImpl) {
this.countImpl = countImpl;
} @Override
public void queryCount() {
System.out.println("事务处理之前");
// 调用委托类的方法;
countImpl.queryCount();
System.out.println("事务处理之后");
} @Override
public void updateCount() {
System.out.println("事务处理之前");
// 调用委托类的方法;
countImpl.updateCount();
System.out.println("事务处理之后");
}
}

4. 测试类:TestCount.java

public class TestCount {
public static void main(String[] args) {
CountImpl countImpl = new CountImpl();
CountProxy countProxy = new CountProxy(countImpl);
countProxy.updateCount();
countProxy.queryCount();
}
}

观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。

二、动态代理

1. 接口类:

public interface PersonService {

    public String getPersonName(Integer personId);

    public void save(String name);

    public void update(Integer personId, String name);
}

2. 实现类:

public class PersonServiceBean implements PersonService {

    public String user = null;

    public PersonServiceBean(){};

    public PersonServiceBean(String user){
this.user = user;
} @Override
public String getPersonName(Integer personId) {
System.out.println("这是find方法"); return this.user;
} @Override
public void save(String name) {
System.out.println("这是save方法");
} @Override
public void update(Integer personId, String name) {
System.out.println("这是update方法");
} public String getUser() {
return user;
} public void setUser(String user) {
this.user = user;
}
}

3. JDK动态代理代理类:

/**
* 切面
*/
public class JDKProxyFactory implements InvocationHandler { private Object proxyObject; //目标对象 /**
* 绑定委托对象并返回一个代理类
* @param proxyObject
* @return
*/
public Object createProxyInstance(Object proxyObject) {
this.proxyObject = proxyObject;
//生成代理类的字节码加载器
ClassLoader classLoader = proxyObject.getClass().getClassLoader();
//需要代理的接口,被代理类实现的多个接口都必须在这里定义 (这是一个缺陷,cglib弥补了这一缺陷)
Class<?>[] proxyInterface = proxyObject.getClass().getInterfaces();
//织入器,织入代码并生成代理类
return Proxy.newProxyInstance(classLoader, proxyInterface, this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
PersonServiceBean bean = (PersonServiceBean)this.proxyObject;
Object result = null;
//控制哪些用户执行切入逻辑
if(bean.getUser() != null) {
//执行原有逻辑
result = method.invoke(this.proxyObject, args);
} return result;
}
}

4. 测试类:

public class AopTest {
@Test
public void proxyTest() {
JDKProxyFactory jpf = new JDKProxyFactory();
PersonServiceBean personService = (PersonServiceBean) jpf.createProxyInstance(new PersonServiceBean("XXX"));
personService.save("888");
}
}

上面是提供了用户名的,所以终端会打印出”我是save()方法“,然后我们将 Java代码

PersonServiceBean personService = (PersonServiceBean)jpf.createProxyInstance(new PersonServiceBean("XXX"));  
改为不提供用户名,即
PersonServiceBean personService = (PersonServiceBean) jpf.createProxyInstance(new PersonServiceBean());  

这时候在允许代码发现终端不打印出"我是save()方法",证明我们的动态代理是成功的。

最新文章

  1. 窗口activity
  2. 【CodeVS 1218】【NOIP 2012】疫情控制
  3. usb host驱动
  4. ionic 报错%1 is not a valid Win32 application
  5. hdu---(1280)前m大的数(计数排序)
  6. struts2 标签的使用之二 s:iterator
  7. 谁说程序员都是苦逼的——看看兄弟连上海S2班的点点滴滴
  8. mina的编码和解码以及断包的处理,发送自己定义协议,仿qq聊天,发送xml或json
  9. ssh 实体关系分析确立(ER图-实体关系图)
  10. 本地yum库的搭建
  11. Flask-WTF 创建表单P2
  12. win10 uwp 修改Pivot Header 颜色
  13. [LeetCode] Longest Word in Dictionary through Deleting 删除后得到的字典中的最长单词
  14. STL--关系型容器
  15. js数据结构与算法——二叉树
  16. angular6、7 兼容ie9、10、11
  17. Ansible常用模块介绍及使用(week5_day1_part2)--技术流ken
  18. js 格式化时间
  19. 转载:编译安装Nginx(1.4)《深入理解Nginx》(陶辉)
  20. Python tuple

热门文章

  1. 从今天开始 每天记录HTML,CSS 部分的学习笔记
  2. Aimbat安装
  3. zepto和jquery关于获取css样式的试用差别
  4. day 29 socket 理论
  5. python 读写、创建 文件的方法(必看)
  6. 如何使用Android Studio把自己的Android library分享到jCenter和Maven Central
  7. Java栈的简单实现
  8. JavaBasic_04
  9. 测试那些事儿—web测试方法之输入框
  10. Atcode ABC105-C:Base -2 Number