博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java之代理设计模式
阅读量:4958 次
发布时间:2019-06-12

本文共 6238 字,大约阅读时间需要 20 分钟。

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

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

这里写图片描述

静态代理

  1. 定义一个接口
package cn.itcast.proxy.sh;public interface PersonDao {    public void savePerson();    public void updatePerson();    public void deletePerson();}

2、 目标类

package cn.itcast.proxy.sh;public class PersonDaoImpl implements PersonDao{
public void deletePerson() { System.out.println("delete person"); } public void savePerson() { System.out.println("save person"); } public void updatePerson() { System.out.println("update person"); }}

3、代理类,包含了目标类和一些额外的操作

package cn.itcast.proxy.sh;public class PersonDaoProxy implements PersonDao{
private PersonDao personDao; private Transaction transaction; public PersonDaoProxy(PersonDao personDao,Transaction transactions){ this.personDao = personDao; this.transaction = transactions; } public void deletePerson() { this.transaction.beginTransaction(); this.personDao.deletePerson(); this.transaction.commit(); } public void savePerson() { this.transaction.beginTransaction(); this.personDao.savePerson(); this.transaction.commit(); } public void updatePerson() { this.transaction.beginTransaction(); this.personDao.updatePerson(); this.transaction.commit(); }}

4、使用

package cn.itcast.proxy.sh;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class ProxyTest {
@Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("cn/itcast/proxy/sh/applicationContext-proxy.xml"); PersonDao personDao = (PersonDao)context.getBean("personDao2"); personDao.deletePerson(); }}

静态代理的缺点

静态代理模式的缺点:

1、如果一个系统中有100Dao,则创建100个代理对象
2、如果一个dao中有很多方法需要事务,则代理对象的方法中重复代码还是很多
3、由第一点和第二点可以得出:proxy的重用性不强

动态代理

1、产生的代理对象和目标对象实现了共同的接口

jdk动态代理
2、代理对象是目标对象的子类
hibernate: Person person = session.load(Person.class,1L); javassisit
spring:cglib动态代理

jdk的动态代理:

1、因为是用jdk的API做到的
2、代理对象是动态产生的
cglib产生的代理类是目标类的子类

注意事项:

1、拦截器中invoke方法体的内容就是代理对象方法体的内容
2、当客户端执行代理对象.方法时,进入到了拦截器的invoke方法体
3、拦截器中invoke方法的method参数是在调用的时候赋值的

jdk动态代理

定义一个接口

package cn.itcast.jdkproxy.sh;public interface PersonDao {    public void savePerson();    public void updatePerson();    public void deletePerson();}

目标类

package cn.itcast.jdkproxy.sh;public class PersonDaoImpl implements PersonDao{
public void deletePerson() { System.out.println("delete person"); } public void savePerson() { System.out.println("save person"); } public void updatePerson() { System.out.println("update person"); }}

拦截器

package cn.itcast.jdkproxy.sh;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;/** * 拦截器 * @author Think *   1、引入目标类 *   2、引入事务 *   3、通过构造函数给目标类和事务赋值 *   4、填充invoke方法 * */public class PersonInterceptor implements InvocationHandler{
private Object target;//目标类 private Transaction transaction;//引入事务 public PersonInterceptor(Object target,Transaction transaction){ this.target = target; this.transaction = transaction; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub this.transaction.beginTransaction(); method.invoke(this.target, args);//调用目标类的方法 this.transaction.commit(); return null; }}

使用

package cn.itcast.jdkproxy.sh;import java.lang.reflect.Proxy;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class ProxyTest {
@Test public void test(){ Object target = new PersonDaoImpl(); Transaction transaction = new Transaction(); PersonInterceptor interceptor = new PersonInterceptor(target, transaction); /** * 1、目标类的类加载器 * 2、目标类实现的所有的接口 * 3、拦截器 */ PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor); personDao.deletePerson(); }}

cglib动态代理

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

目标类

package net.battier.dao.impl;   /**   * 这个是没有实现接口的实现类   *    * @author student   *    */   public class BookFacadeImpl1 {
public void addBook() { System.out.println("增加图书的普通方法..."); } }

拦截类

package net.battier.proxy;  import java.lang.reflect.Method;  import net.sf.cglib.proxy.Enhancer;  import net.sf.cglib.proxy.MethodInterceptor;  import net.sf.cglib.proxy.MethodProxy;  /**  * 使用cglib动态代理  *   * @author student  *    */   public class BookFacadeCglib implements MethodInterceptor {
private Object target; /** * 创建代理对象 * * @param target * @return */ public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); // 回调方法 enhancer.setCallback(this); // 创建代理对象 return enhancer.create(); } @Override // 回调方法 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("事物开始"); proxy.invokeSuper(obj, args); System.out.println("事物结束"); return null; } }

使用

package net.battier.test;  import net.battier.dao.impl.BookFacadeImpl1;  import net.battier.proxy.BookFacadeCglib;  public class TestCglib {
public static void main(String[] args) { BookFacadeCglib cglib=new BookFacadeCglib(); BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1()); bookCglib.addBook(); } }

参考链接

转载于:https://www.cnblogs.com/jjx2013/p/6223679.html

你可能感兴趣的文章
生成php所需要的APNS Service pem证书的步骤
查看>>
JavaWeb之JSON
查看>>
URL中的特殊字符处理
查看>>
HOT SUMMER 每天都是不一样,积极的去感受生活 C#关闭IE相应的窗口 .
查看>>
windows平台上编译mongdb-cxx-driver
查看>>
optionMenu-普通菜单使用
查看>>
MVC3分页传2参
查看>>
2016-2017-2点集拓扑作业[本科生上课时]讲解视频
查看>>
appium(13)- server config
查看>>
IIS负载均衡-Application Request Route详解第六篇:使用失败请求跟踪规则来诊断ARR...
查看>>
管理信息系统 第三部分 作业
查看>>
[Leetcode Week13]Search a 2D Matrix
查看>>
通过被调函数改变主调函数的值
查看>>
java 对象的序列化与反序列化
查看>>
二叉树、树、森林
查看>>
查看端口占用cmd命令
查看>>
2019.01.17王苛震作业
查看>>
Halcon学习(八)文本操作
查看>>
MFC电子词典
查看>>
简单工厂(Simple Factory)
查看>>