【编程不良人】快速入门Spring学习笔记05---静态代理和动态代理

本文回顾了Spring框架的基础知识,包括Spring Core、配置文件、依赖注入和单例/多例工厂。深入探讨了如何使用Spring AOP解决业务层代码冗余,通过静态代理和动态代理实现事务管理。

0.Day01知识回顾

配套视频:【编程不良人】快速入门Spring,SpringBoot、SpringCloud学不好完全是因为Spring没有掌握!_哔哩哔哩_bilibili

a.spring框架?

spring 框架是一个项目管理框架,核心是用来管理项目中组件对象的创建、使用、销毁。

b.spring框架第一个环境搭建

1).引入依赖

   spring-core
   spring-context
   spring-beans
   spring-expression
   spring-jdbc
   spring-web
   .....

2).引入配置文件spring.xml

  
   名字 随便  位置:resources目录下随便

3).通过spring管理组件的创建

  interface UserDAO { void save(String name)}
  class UserDAOImpl implements UserDAO
  ​
  spring.xml
   <bean clsss="xxx.UserDAOImpl" id="userDAO" />

4).启动工厂

  
  ApplicationContext  context = new ClassPathXmlApplicationContext("xxx/spring.xml");
  context.getBean("beanid");

c.spring核心思想

  
  IOC&DI
      IOC:inversion of control 控制反转
          就是将手动通过new关键字创建对象的权利交给spring,由工厂创建对象的过程
      DI: Dependency Injection 依赖注入
          Spring工厂不仅要创建对象,还要在创建对象的同时维护组件和组件的依赖关系
  ​
  AOP: 面前切面编程

d.spring中的注入方式

  
  SET方式[重点]    构造方法   自动注入
  SET注入:
          定义: 使用set方法形式为成员变量赋值过程称之为set注入
          语法:
               1.需要谁将谁声明为成员变量并提供公开SET方法
               2.在spring配置文件中对应组件标签内部使用 property标签完成注入
  ​
          1.String + 八种基本类型 + 日期类型 使用 value属性进行注入
              <property name="name" value="xx">
              注意: spring中日期格式 默认为 yyyy/MM/dd HH:mm:ss
  ​
          2.对象|引用类型
              <property name="" ref="beanid">
  ​
          3.数组类型
              array   基本:value     引用: ref bean="beanid"
  ​
          4.list set map
              list    基本:value     引用: ref
              map  entry   基本:key="" value=""  引用: key-ref="beanid" value-ref="beanid"
  ​
          5.properties
              props  prop  key=""   <prop key="">value</prop>

e.spring工厂细节

  1).创建方式 默认使用单例
      <bean class="" id="" scope="singleton(service dao)|prototype(struts2action)">
  ​
  2).工厂原理
      反射+构造方法
      Class.forName("xxxx").newInstance();
  ​
  3).工厂生命周期
      单例: 工厂启动,工厂中单例对象随之创建;工厂正常关闭,工厂中单例对象随之销毁
      多例: 每次使用时工厂进行多例对象的创建;spring工厂不负责多例对象的销毁

=================Spring中AOP

  
  AOP:     面向切面的编程
  java :  (Proxy)代理

1.现有业务层开发存在问题

配套视频:【编程不良人】快速入门Spring,SpringBoot、SpringCloud学不好完全是因为Spring没有掌握!_哔哩哔哩_bilibili

a.定义业务接口

  public interface UserService {
      void save(String name);
      void delete(String id);
      void update();
      String findAll(String name);
      String findOne(String id);
  }

b.实现业务接口

  public class UserServiceImpl implements UserService {
      @Override
      public void save(String name) {
          try {
              System.out.println("开启事务");
              System.out.println("处理业务逻辑,调用DAO~~~");
              System.out.println("提交事务");
          }catch (Exception e){
              System.out.println("回滚事务");
              e.printStackTrace();
          }
      }
  ​
      @Override
      public void delete(String id) {
          try {
              System.out.println("开启事务");
              System.out.println("处理业务逻辑,调用DAO~~~");
              System.out.println("提交事务");
          }catch (Exception e){
              System.out.println("回滚事务");
              e.printStackTrace();
          }
      }
  ​
      @Override
      public void update() {
          try {
              System.out.println("开启事务");
              System.out.println("处理业务逻辑,调用DAO~~~");
              System.out.println("提交事务");
          }catch (Exception e){
              System.out.println("回滚事务");
              e.printStackTrace();
          }
      }
  ​
      @Override
      public String findAll(String name) {
          try {
              System.out.println("开启事务");
              System.out.println("处理业务逻辑,调用DAO~~~");
              System.out.println("提交事务");
          }catch (Exception e){
              System.out.println("回滚事务");
              e.printStackTrace();
          }
          return name;
      }
  ​
      @Override
      public String findOne(String id) {
          try {
              System.out.println("开启事务");
              System.out.println("处理业务逻辑,调用DAO~~~");
              System.out.println("提交事务");
          }catch (Exception e){
              System.out.println("回滚事务");
              e.printStackTrace();
          }
          return id;
      }
  }

问题:从上面的代码可以发现,现有业务层中控制事务代码出现了大量的冗余,如何解决现有业务层出现的冗余问题? 下面从代理的角度进行分析。


2.代理引言

a.什么是代理?

代理: 指的是java中的一种设计模式

b.为什么需要代理?

很多时候除了当前类能够提供的功能外,我们还需要补充一些额外功能。

c.代理的作用

代理对象可以在客户和目标对象之间起到中介作用,从而为目标对象增添额外的功能。

d.代理图例


3.静态代理的开发

目标类|对象(target): 被代理类称之为目标类 或者 被代理的对象的称之为目标对象

开发代理的原则: 代理类和目标类功能一致且实现相同的接口, 同时代理类中依赖于目标类对象

a.开发静态代理类

  //静态代理类
  //开发原则: 代理类和目标类实现相同接口,依赖于真正的目标类
  public class UserServiceStaticProxy implements UserService {
      //真正的目标类 target 原始业务逻辑对象
      private UserService userService;
      public void setUserService(UserService userService) {
          this.userService = userService;
      }
  ​
      @Override
      public void save(String name) {
          try {
              System.out.println("开启事务");
              userService.save(name);//调用真正业务逻辑方法
              System.out.println("提交事务");
          }catch (Exception e){
              System.out.println("回滚事务");
              e.printStackTrace();
          }
      }
  ​
      @Override
      public void delete(String id) {
          try {
              System.out.println("开启事务");
              userService.delete(id);//调用真正业务逻辑方法
              System.out.println("提交事务");
          }catch (Exception e){
              System.out.println("回滚事务");
              e.printStackTrace();
          }
      }
  ​
      @Override
      public void update() {
          try {
              System.out.println("开启事务");
              userService.update();//调用真正业务逻辑方法
              System.out.println("提交事务");
          }catch (Exception e){
              System.out.println("回滚事务");
              e.printStackTrace();
          }
      }
  ​
      @Override
      public String findAll(String name) {
          try {
              System.out.println("开启事务");
              String result = userService.findAll(name);//调用真正业务逻辑方法
              System.out.println("提交事务");
              return result;
          }catch (Exception e){
              System.out.println("回滚事务");
              e.printStackTrace();
          }
          return null;
      }
  ​
      @Override
      public String findOne(String id) {
          try {
              System.out.println("开启事务");
              //调用目标类方法
              String one = userService.findOne(id);//调用真正业务逻辑方法
              System.out.println("提交事务");
              return one;
          }catch (Exception e){
              System.out.println("回滚事务");
              e.printStackTrace();
          }
          return null;
      }
  }

b.更改目标实现类

  
  package staticproxy;
  ​
  public class UserServiceImpl implements UserService{
      @Override
      public void save(String name) {
          System.out.println("处理业务逻辑,调用saveDAO方法");
      }
  ​
      @Override
      public void delete(String id) {
          System.out.println("处理业务逻辑,调用deleteDAO方法");
      }
  ​
      @Override
      public void update() {
          System.out.println("处理业务逻辑,调用updateDAO方法");
      }
  ​
      @Override
      public String findOne(String id) {
          System.out.println("处理业务逻辑,调用findOneDAO方法");
          return id;
      }
  ​
      @Override
      public String findAll(String name) {
          System.out.println("处理业务逻辑,调用findAllDAO方法");
          return name;
      }
  }

c.配置静态代理类

  
  <?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 class="staticproxy.UserServiceImpl" id="userService"/>
      <!--配置代理类-->
      <bean class="staticproxy.UserServiceStaticProxy" id="userServiceStaticProxy">
          <!--注入目标对象-->
          <property name="userService" ref="userService"/>
      </bean>
  </beans>

d.调用代理方法

  package staticproxy;
  ​
  import org.springframework.context.ApplicationContext;
  import org.springframework.context.support.ClassPathXmlApplicationContext;
  ​
  public class TestSpring {
      public static void main(String[] args) {
          ApplicationContext context = new ClassPathXmlApplicationContext("staticproxy/spring.xml");
          UserService userService = (UserService)context.getBean("userServiceStaticProxy");
          userService.save("小崔");
      }
  }
  ​

新的问题:往往在开发时我们书写的业务层会有很多,如果为每一个业务层开发一个静态代理类,不仅没有减轻工作量,甚至让我们的工作量多了一倍不止怎么解决以上这个问题呢?

解决方案:为业务层在运行过程中动态创建代理类,通过动态代理类去解决我们现有业务层中业务代码冗余的问题。

4.动态代理的原理

通过jdk提供的Proxy这个类动态的为现有的业务生成代理类

  
  package staticproxy;
  ​
  import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Method;
  import java.lang.reflect.Proxy;
  ​
  public class TestDynamicProxy {
      public static void main(String[] args) {
          //动态代理:指的是在程序运行过程中动态通过代码的方式为指定的类生成动态代理对象
          //目标对象 或 被代理对象
          UserService userService = new UserServiceImpl();
  ​
          //参数1:classLoader 类加载器
          ClassLoader classLoader = Thread.currentThread().getContextClassLoader();//当前线程类加载器
          //参数2:Class[] 生成代理类的接口类型 / 目标对象接口类型的数组
          Class[] classes = {UserService.class};
          //参数3:InvocationHandler接口类型,其中的invoke方法用来书写额外的附加功能
          //      通过代理类对象调用方法时会优先进入参数3中的invoke方法
          //dao UserDAO userDAO = sqlSession.getMapper(userDAO.class); userDAO.save()=
          //返回值proxy就是生成的动态代理对象
          UserService proxy = (UserService)Proxy.newProxyInstance(classLoader, classes, new InvocationHandler() {
              @Override
              //通过动态代理对象调用自己里面代理方法会优先指定InvocationHandler类中的invoke
              //参数1:proxy 当前创建好的代理对象
              //参数2:method 当前代理对象执行的方法对象
              //参数3:args 当前代理对象执行方法的参数
              public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                  //mapper文件xml save id=“save” sql+jdbc+pstm args   mybatis底层实现原理是动态代理
                  System.out.println("当前执行的方法:" + method.getName());
                  System.out.println("当前执行的方法中的参数:" + args[0]);
  ​
                  try {
                      System.out.println("开启事务");//附加操作
                      //调用目标类中业务方法通过反射机制调用目标类中当前方法
                      Object invoke = method.invoke(new UserServiceImpl(),args);
                      System.out.println("提交事务");//附加操作
                      return invoke;
                  } catch (Exception e) {
                      System.out.println("回滚事务");//附加操作
                      e.printStackTrace();
                  }
                  return null;
              }
          });
          System.out.println(proxy.getClass());
          //通过动态代理对象调用代理中方法
          String result = proxy.findAll("小崔");
          System.out.println(result);
      }
  }
  ​
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值