Java研学-代理模式

这篇具有很好参考价值的文章主要介绍了Java研学-代理模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一 概述

1 分类

  静态代理:在程序运行前就已经存在代理类的字节码文件,代理对象和真实对象的关系在运行前就确定了。(代理类及对象要自行创建)
  动态代理:代理类是在程序运行期间由 JVM 通过反射等机制动态的生成的,不存在代理类的字节码文件,动态生成字节码对象,代理对象和真实对象的关系是在程序运行时期才确定的。(代理类及对象不需要自行创建)

2 动态代理实现方式

  真实类有接口使用 JDK 动态代理;
  真实类没实现接口使用 CGLIB 或 Javassist 组件。

二 静态代理

1 介绍

  静态代理是一种代理模式,其中代理对象在编译时就确定下来,而不是在运行时动态创建。静态代理由业务实现类、业务代理类两部分组成。业务实现类负责实现主要的业务方法,业务代理类负责对调用的业务方法作拦截、过滤、预处理。

  静态代理的优点是可以实现对目标方法的扩展,控制真实对象的访问权限,避免创建大对象,以及增强真实对象功能。业务类只需要关注业务逻辑本身,保证了业务类的重用性。把真实对象隐藏起来了,保护真实对象。

  缺点是如果一个代理类只能对一个业务接口的实现类进行包装,如果有多个业务接口的话就要定义很多实现类和代理类才行。而且,如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很多重复代码。
Java研学-代理模式,# Java研学,java,代理模式,开发语言

2 导入依赖

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.8.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.0.8.RELEASE</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

3 业务类

// 真实类与代理类需实现相同的接口
public interface EmployeeService {
    /*员工保存*/
    public int save(String username,String password);
}
// 真实类
public class EmployeeServiceImpl implements EmployeeService {
    @Override
    public int save(String username, String password) {
        System.out.println("员工姓名:"+username+"密码:"+password);
        return 0;
    }
}

4 代理类

public class EmployeeServiceProxy implements EmployeeService {
    /*setter注入真实对象,增加事务操作*/
    private EmployeeServiceImpl employeeService;
    public void setEmployeeService(EmployeeServiceImpl employeeService) {
        this.employeeService = employeeService;
    }
    /*setter注入事务管理对象*/
    private TransactionManager transactionManager;
    public void setTransactionManager(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }
    /*执行真实对象的业务方法以及事务方法*/
    @Override
    public int save(String username, String password) {
        try {
            /*开启事务*/
            transactionManager.begin();
            /*调用真实的业务方法*/
            employeeService.save(username,password);
            /*设置异常*/
            int num=10/0;
            /*提交事务*/
            transactionManager.commit();
        } catch (Exception e) {
            /*事务回滚*/
            transactionManager.rollback();
            e.printStackTrace();
        }
        return 0;
    }
}

5 事务类

public class TransactionManager {
    /*开启事务*/
    public void begin(){
        System.out.println("事务开启了.....");
    }
    /*提交事务*/
    public void commit(){
        System.out.println("事务提交了........");
    }
    /*回滚事务*/
   public void rollback(){
       System.out.println("事务回滚了.........");
   }
}

6 resources配置文件 – spring-core.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--事务管理对象-->
    <bean id="transactionManager" class="cn.tj.tx.TransactionManager"></bean>
    <!--代理对象 为代理对象注入2Bean-->
    <bean id="employeeServiceProxy" class="cn.tj.proxy.EmployeeServiceProxy">
        <property name="transactionManager" ref="transactionManager"></property>
        <property name="employeeService" >
            <bean class="cn.tj.service.impl.EmployeeServiceImpl"></bean>
        </property>
    </bean>
</beans>

7 测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-core.xml")
public class EmployeeServiceTest {
	// employeeServiceProxy是bean的id 要一致
    @Autowired
    private EmployeeService employeeServiceProxy;
    @Test
    public void emp_save() {
        //调用代理对象的方法
        employeeServiceProxy.save("叶凡","19216875523");
    }
}

三 JDK 动态代理

1 API

① java.lang.reflect.Proxy
  Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。

// 主要方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler hanlder)

// 参数
loader :类加载器,一般传递真实对象的类加载器;
interfaces:代理类需要实现的接口;
handler:代理执行处理器,说人话就是生成代理对象帮你要做什么。
返回:创建的代理对象。

// 作用
为指定类加载器、一组接口及调用处理器生成动态代理类实例。

② java.lang.reflect.InvocationHandler
  由代理类实例的调用处理程序实现的接口

// 主要方法
public Object invoke(Object proxy, Method method, Object[] args)

// 参数
proxy :生成的代理对象;
method:当前调用的真实方法对象;
args :当前调用方法的实参。
返回:真实方法的返回结果。

// 作用
负责集中处理动态代理类上的所有方法调用,让使用者自定义做什么事情,对原来方法增强(加什么功能)。

2 代理类 – TransactionInvocationhandler

// jdk动态代理执行器 实现 InvocationHandler 接口,实现 invoke 方法,实现增强操作
public class TransactionInvocationhandler implements InvocationHandler {
    /*注入真实对象:程序运行起来之后才会知道是什么对象*/
    private Object object;
    public void setObject(Object object) {
        this.object = object;
    }
    public Object getObject() {
        return object;
    }
    /*注入扩展对象:事务对象*/
    private TransactionManager transactionManager;
    public void setTransactionManager(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }
   
    /*将真实业务方法和扩展方法组合执行*/
    @Override
    public Object invoke(Object proxy,
                         Method method,
                         Object[] args) throws Throwable {
        Object o=null;
        try {
            /*开启事务*/
            transactionManager.begin();
            /*执行真实对象的方法:反射调用类成员方法*/
             o= method.invoke(object,args);

            /*设置异常*/
			// int num=10/0;
            /*提交事务*/
            transactionManager.commit();
        } catch (Exception e) {
            e.printStackTrace();
            /*回滚事务*/
            transactionManager.rollback();
        }
        return o;
    }
}

3 配置文件 – spring-core.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--事务管理对象-->
    <bean id="transactionManager" class="cn.tj.tx.TransactionManager"></bean>
    <!--代理执行器对象-->
    <bean id="transactionInvocationhandler" class="cn.tj.proxy.TransactionInvocationhandler">
        <property name="transactionManager" ref="transactionManager"></property>
        <property name="object" >
            <bean class="cn.tj.service.impl.EmployeeServiceImpl"></bean>
        </property>
    </bean>
</beans>

4 真实类接口实现类与事务类不变

5 测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-core.xml")
public class EmployeeServiceTest {
    @Autowired
    private TransactionInvocationhandler transactionInvocationhandler;
    @Test
    public void emp_save() {
       //创建代理对象 (静态方法) 返回值应为service 默认为Object 故强转
        EmployeeService employePproxy = (EmployeeService) Proxy.newProxyInstance(
                transactionInvocationhandler.getObject().getClass().getClassLoader(),//通过执行器对象获取到真实对象的类加载器
                transactionInvocationhandler.getObject().getClass().getInterfaces(),//通过执行器对象获取真实对象实现的接口
                transactionInvocationhandler);
        System.out.println(employePproxy);
        //调用代理对象的方法
//        employePproxy.save("李四","333333");
    }
}

四 CGLIB 动态代理

1 API

① org.springframework.cglib.proxy.Enhancer

  Enhancer是CGLIB中用于字节码增强的类,类似于JDK动态代理中的Proxy类。它能够代理普通Java类和接口,通过创建一个被代理类的子类来拦截所有的方法调用。Enhancer的主要方法包括setSuperclass设置代理类的父类,setCallback设置回调函数等。

② org.springframework.cglib.proxy.InvocationHandler

  类似 JDK 中 InvocationHandler,CGLIB 库中的一个接口,用于拦截目标对象的代理方法调用。当一个代理对象被调用时,会先调用该接口的实现类中的invoke方法,然后才会调用目标对象的方法

2 代理类 – TransactionInvocationhandler

// 导入cglib包的InvocationHandler 
public class TransactionInvocationhandler implements InvocationHandler {
    /*注入真实对象:程序运行起来之后才会知道是什么对象*/
    private Object object;
    public void setObject(Object object) {
        this.object = object;
    }
    public Object getObject() {
        return object;
    }
    /*注入扩展对象:事务对象*/
    private TransactionManager transactionManager;
    public void setTransactionManager(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }
    /*将真实业务方法和扩展方法组合执行*/
    @Override
    public Object invoke(Object proxy,
                         Method method,
                         Object[] args) throws Throwable {
        Object o=null;
        try {
            /*开启事务*/
            transactionManager.begin();
            /*执行真实对象的方法:反射调用类成员方法*/
             o= method.invoke(object,args);

            /*设置异常*/
//            int num=10/0;
            /*提交事务*/
            transactionManager.commit();
        } catch (Exception e) {
            e.printStackTrace();
            /*回滚事务*/
            transactionManager.rollback();
        }
        return o;
    }
}

3 测试类

// 只须修改代理类和测试类 其他与jdk代理相同
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-core.xml")
public class EmployeeServiceTest {
    @Autowired
    private TransactionInvocationhandler transactionInvocationhandler;
    @Test
    public void emp_save() {
       //创建代理对象的生成类对象 通过他创建代理对象
        Enhancer enhancer=new Enhancer();
        //设置代理对象和真实对象的继承关系 将真实对象设为代理对象的父类
        enhancer.setSuperclass(transactionInvocationhandler.getObject().getClass());
        //设置代理对象需要执行的操作 形参为callback 实际传递为他的继承类的实现类
        enhancer.setCallback(transactionInvocationhandler);
        //创建代理对象
        EmployeeServiceImpl employeeService = (EmployeeServiceImpl) enhancer.create();
        //调用代理对象的方法
        employeeService.save("陈汉生","admin");
    }
}

五 动态代理小结

1 JDK 动态代理

  Java 动态代理是使用 java.lang.reflect 包中的 Proxy 类与 InvocationHandler 接口这两个来完成的。要使用 JDK 动态代理,真实类必须实现接口。JDK 动态代理将会拦截所有 pubic 的方法(因为只能调用接口中定义的方法),这样即使在接口中增加了新的方法,不用修改代码也会被拦截。
  动态代理的最小单位是类(类中某些方法都会被处理),如果只想拦截一部分方法,可以在 invoke 方法中对要执行的方法名进行判断。(代理类与真实类共同实现相同接口)

2 CGLIB 动态代理

  CGLIB 可以生成真实类的子类,并重写父类非 final 修饰符的方法。要求类不能是 final 的,要拦截的方法要是非 final、非 static、非 private 的。
  动态代理的最小单位是类(类中某些方法都会被处理),如果只想拦截一部分方法,可以在 invoke 方法中对要执行的方法名进行判断。(代理类是继承真实类)

3 选择

  从性能上看:Javassit 优于 CGLIB 优于 JDK,JDK 动态代理是基于实现接口的,CGLIB 和 Javassit 是基于继承真实类的。
  真实类实现了接口,优先选用 JDK 动态代理。若真实类没实现任何接口,使用 Javassit 和 CGLIB 动态代理。文章来源地址https://www.toymoban.com/news/detail-823991.html

到了这里,关于Java研学-代理模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java代理模式——静态代理与动态代理

    代理模式允许你为其他对象提供一个代理,以控制对这个对象的访问。代理模式在不改变实际对象的情况下,可以在访问对象时添加额外的功能。 可以理解为代理模式为被代理对象创造了一个替身,调用者可以通过这个替身去实现这个被代理对象的功能,这个替身也可以为被

    2024年02月13日
    浏览(47)
  • Java设计模式(十三)代理模式

    一、概述 代理模式是一种结构型设计模式,它提供了一个代理对象,充当被代理对象的接口,以控制对被代理对象的访问。代理模式可以在不修改被代理对象的情况下,增加额外的功能或控制访问方式。 二、代码 以下是一个示例代码,说明代理模式的使用: 在上述代码中,

    2024年02月04日
    浏览(41)
  • 【Java设计模式005】代理模式

    由于一些特定原因某些对象不适合或者不能直接引用目标对象,这时就可以使用代理模式。代理模式为目标对象提供一个代理以控制访问对象对目标对象的访问。客户端只能直接访问代理对象,不能直接访问目标对象,这么做确保了目标对象的安全。生活中一个常见的例子就

    2024年02月12日
    浏览(41)
  • 基于Java的设计模式 - 代理模式

    代理模式是一种使用代理对象来执行目标对象的方法并在代理对象中增强目标对象方法的一种设计模式。简单来讲就是在不修改目标对象的基础上,增强主业务逻辑的设计模式。 代理模式基本可分为三种 静态代理 JDK动态代理 CGLIB动态代理 上述简单分就是静态和动态代理,静

    2024年02月07日
    浏览(37)
  • Java 与设计模式(13):代理模式

    代理模式是一种结构型设计模式,用于在访问对象时引入一个代理对象,以控制对实际对象的访问。代理对象充当了客户端和实际对象之间的中介,客户端通过代理对象间接地访问实际对象,从而可以在访问过程中添加额外的逻辑或控制。代理模式可以提供对实际对象的保护

    2024年02月09日
    浏览(38)
  • Java设计模式---单例 工厂 代理模式

    单例模式是设计模式中的一种,属于创建型模式。在软件工程中,单例模式确保一个类只有一个实例,并提供一个全局访问点。这种模式常用于那些需要频繁实例化然后引用,且创建新实例的开销较大的类,例如数据库连接池、缓存管理等。 意图 :保证一个类仅有一个实例

    2024年01月24日
    浏览(52)
  • 代理模式(Java实现)

    代理模式是常见的设计模式之一,顾名思义,代理模式就是代理对象具备真实对象的功能,并代替真实对象完成相应操作,并能够在操作执行的前后,对操作进行增强处理。(为真实对象提供代理,然后供其他对象通过代理访问真实对象) 分为 静态代理 动态代理 jdk动态代理

    2024年02月12日
    浏览(37)
  • Java中的代理模式

    接口 目标类 代理类 测试 接口 目标类 动态代理类 测试 总结: 动态生成代理类 通过实现接口生成代理类(目标接口必须实现接口) 代理类是实现接口的方式 调用目标类使用反射调用 目标类调用本类方法只会代理一次 目标类 代理类 测试 总结 通过ASM第三方框架动态代理 无需接

    2024年02月15日
    浏览(38)
  • Java 代理模式

    目标类和代理类,不是直接调用目标类对象,而是通过调用代理类的对象的方法,代理类来帮我们访问目标类对象,这样我们就可以在代理类上添加更多需要的扩展功能,而目标类不用改动,只用实现自身的主要功能。 代理类是为了扩展目标类的功能,代理类和目标类的产出

    2024年02月10日
    浏览(26)
  • 代理模式(java)

    目录 结构 静态代理案例  代码实现 售票类 火车站类 代理类 测试类 优缺点 优点 缺点 代理(Proxy)模式分为三种角色: 抽象主题(Subject)类 : 通过接口或抽象类声明真实主题和代理对象实现的业务方法。 真实主题(Real Subject)类 : 实现了抽象主题中的具体业务,是代理

    2024年02月16日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包