Spring IOC实战指南:从零到一的构建过程

Spring 优点:

  1. 方便解耦,简化开发。将所有对象创建和依赖关系维护交给 Spring 管理(IOC 的作用)
  2. AOP 切面编程的支持。方便的实现对程序进行权限的拦截、运行监控等功能(可扩展性)
  3. 声明式事务的支持。只需通过配置就可以完成对事务的管理,无需手动编程
  4. 方便程序测试。Spring 对 junit4 支持,可以通过注解方便测试 Spring 程序
  5. 方便集成各种优秀框架
  6. 降低 API 的使用难度

IOC:控制权反转

  1. 作用:

    1. 将创建对象的过程交给 Spring 框架进行管理
    2. 降低代码的耦合度。利用 IOC 容器进行控制
      1. 一个程序失控后不会影响其他程序的运转
  2. 使用:

    1. 创建 Maven 项目,导入依赖:

      <dependencies>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>5.0.2.RELEASE</version>
          </dependency>
          <dependency>
              <groupId>commons-logging</groupId>
              <artifactId>commons-logging</artifactId>
              <version>1.2</version>
          </dependency>
          <dependency>
              <groupId>log4j</groupId>
              <artifactId>log4j</artifactId>
              <version>1.2.12</version>
          </dependency>
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.12</version>
              <scope>test</scope>
          </dependency>
      </dependencies>
      
    2. 项目基本结构:

    3. 编写 Spring 核心的配置文件:

      1. 在 resources 下边创建 application.xml 文件
    4. xml 方式创建对象:

      <!--IOC容器管理的bean-->
      <!--利用spring工厂创建对象-->
      <!--id: 唯一表示符 -> 对象名称 -->
      <!--class: 类的全路径-->
      <bean id="userService" class="com.qcby.spring.service.impl.UserServiceImpl" />
      
    5. 测试类:

      public class TestIOC {
      
          //传统调用
          @Test
          public void run(){
              UserServiceImpl userService = new UserServiceImpl();
              userService.sayHello();
          }
      
          //Spring 创建对象写法
         @Test
          public void  run(){
              ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
              UserServiceImpl userService = (UserServiceImpl) applicationContext.getBean("userService");
              userService.sayHello();
          }
      }
      
  3. IOC 技术总结:

    1. ApplicationContext 接口:工厂的接口,使用接口可以获取到具体的 Bean 对象
    2. 该接口下有两个实现类,SpringCould 配置中心:
      1. ClassPathXmlApplicationContext:加载类路径下的 Spring 配置文件
      2. FileSystemXmlApplicationContext:加载本地磁盘下的 Spring 配置文件

Spring 对对象的管理:

  1. 分类:
    1. 基于配置文件的方式:
      1. 创建对象
      2. 注入属性
    2. 基于注解方式实现:
      1. 创建对象
      2. 注入属性
  2. Spring 框架的 Bean 管理的配置文件的方式:
    1. ID 属性:
      1. 给 Bean 起个名字,在约束中采用 ID 的唯一约束
      2. 取值要求:必须以字母开始,可以使用字母、数字、下划线、句号、冒号。不能出现特殊字符
    2. class 属性:Bean 对象的全路径
    3. scope 属性:scope 属性代表 Bean 的作用范围
    4. singleton 属性:表示单例 (默认值),最常用的方式
    5. prototype 属性:应用在 Web 项目中,同一个 HTTP Session 共享一个 Bean
  3. Bean 对象的创建和销毁的两个属性配置:
    1. 说明:
      1. Spring 初始化 Bean 或销毁 Bean 时,有时需要做一些处理工作,因此 spring 可以在创建和拆卸 bean 的时候调用 bean 的两个声明周期方法
    2. init-method 属性:当 bean 被加载到容器的时候用 init-method 属性指定的方法
    3. destory-method 属性:当 bean 从容器中删除的时候用 destory-method 属性指定的方法
  4. 实例化 Bean 对象的三种方法:
    1. 默认无参数的构造方法(默认方法,基本使用)

      <bean id="userService" class="com.qcby.spring.service.impl.UserServiceImpl" >
          <property name="name" value="张三"/>
          <property name="age" value="44"/>
      </bean>
      
    2. 静态工厂实例化方法:

      /**
       * 静态工厂方式
       */
      public class StaticFactory {
          
          //静态工厂方式
          public static UserService creatUs(){
              System.out.println("静态工厂方式创建 UserServiceImpl对象");
              
              //业务逻辑 + 权限校验
              
              return new UserServiceImpl();
          }
      }
      
      //配置文件
      <bean id="us" class="com.qcby.spring.factory.StaticFactory" factory-method="creatUs"></bean>
      
    3. 动态工厂实例化方法:

      /**
       * 动态工厂实例化方式
       */
      public class Dfactory {
          public UserService craeatUs(){
              System.out.println("动态实例化工厂的方式");
              //业务逻辑 + 权限校验
              
              return new UserServiceImpl();
          }
      }
      
      //配置文件
      <bean id="dfactory" class="com.qcby.spring.factory.Dfactory"></bean>
      <bean id="us" factory-bean="dfactory" factory-method="craeatUs"></bean>
      

DI:依赖注入

  1. IOC 和 DI 的概念:

    1. IOC:Inverse of Control,控制权反转,将对象创建权反转给 Spring
    2. DI:Dependency Injection,依赖注入,在 Spring 框架负责创建 Bean 对象时,动态的将依赖对象注入到 Bean 组件中
  2. set 方法注入属性:

    1. <property name="" value = "" />

    2. 注意:给类、集合、列表和 map 集合,property 类型赋值的方式

    3. 实体类:

      public class User {
          private String name;
          private Integer age;
          private Demo demo;
          private String[] strs;
          List<String> list;
          Map<String,String> map;
      
          @Override
          public String toString() {
              return "User{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      ", demo=" + demo +
                      ", strs=" + Arrays.toString(strs) +
                      ", list=" + list +
                      ", map=" + map +
                      '}';
          }
      
         //get set 方法
      
    4. 注入属性:

          <!--IOC容器管理的bean-->
          <!--id:唯一表示符-->
          <!--class:类的全路径-->
          <bean id="demo" class="com.spring.service.Demo"/>
          <bean id="uesr" class="com.spring.service.User">
              <property name="name" value="张三"/>
              <property name="age" value="18"/>
              
      <!--        给对象赋值  &ndash;&gt; 用 ref 属性   首先要有这个对象-->
              <property name="demo" ref="demo"/>
              
      <!--        给数组赋值 利用 <array></array>-->
              <property name="strs">
                  <array>
                      <value>熊大</value>
                      <value>熊二</value>
                  </array>
              </property>
              
              <!--给list列表赋值利用  <list></list>-->
              <property name="list">
                  <list>
                      <value>张胜男</value>
                      <value>理事长</value>
                  </list>
              </property>
              
              <!--给 map 赋值
                <map>  
                      <emtry key = ""  value = "" /> 
               </map>-->
              <property name="map">
                  <map>
                      <entry key="张三" value="河北"/>
                      <entry key="李思思" value="北京"/>
                  </map>
              </property>
          </bean>
      </beans>
      
  3. 利用构造器注入属性:

    1. <constructor-arg name = '' " value = " ">

    2. 实体类:

      public class User {
          private String name;
          private Integer age;
          private Demo demo;
          private String[] strs;
          List<String> list;
          Map<String,String> map;
      
          public User(String name, Integer age, Demo demo, String[] strs, List<String> list, Map<String, String> map) {
              this.name = name;
              this.age = age;
              this.demo = demo;
              this.strs = strs;
              this.list = list;
              this.map = map;
          }
      
          @Override
          public String toString() {
              return "User{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      ", demo=" + demo +
                      ", strs=" + Arrays.toString(strs) +
                      ", list=" + list +
                      ", map=" + map +
                      '}';
          }
      
          
      }
      
    3. 注入数据:

       <!--IOC容器管理的bean-->
          <!--id:唯一表示符-->
          <!--class:类的全路径-->
          <bean id="demo" class="com.spring.service.Demo"/>
          <bean id="user" class="com.spring.service.User">
              <constructor-arg name="name" value="张胜男"/>
              <constructor-arg name="age" value="18"/>
      
              <!--给对象赋值 利用 ref -->
              <constructor-arg name="demo" ref="demo"/>
      
              <!--给数组赋值-->
              <constructor-arg name="strs">
                  <array>
                      <value>张思思</value>
                      <value>王菲</value>
                      <value>李思琪</value>
                  </array>
              </constructor-arg>
      
              <!--给 list 列表赋值-->
              <constructor-arg name="list">
                  <list>
                      <value>1111</value>
                      <value>aaaa</value>
                  </list>
              </constructor-arg>
      
              <!--给 map 集合赋值 利用 entry-->
              <constructor-arg name="map">
                  <map>
                      <entry key="111" value="sss"/>
                      <entry key="222" value="aaa"/>
                  </map>
              </constructor-arg>
              
              <!--给 property 类型赋值
              内部是  key  value 形式
              -->
              <constructor-arg name = "properties">
                  <props>
                      <prop key = "username">root</prop>
                      <prop key = "age">18</prop>
                  </props>
              </constructor-arg>
          </bean>
      </beans>
      

注解创建对象:

  1. 配置扫描固定的包:

    1. 作用:把当前类使用 IOC 容器进行管理,如果没有指定名称,默认使用类名,首字母小写方式命名

      //扫描固定包下的文件
      <context:component-scan base-package="com.spring.service"/>
      
  2. bean 管理类常用注解:

    1. @Component():普通的类

    2. @Controller():表现层

    3. @Service():业务层

    4. @Repository():持久层

      @Component(value = "user")
      //@Controller()
      //@Service()
      //@Repository()
      public class user{
          @Value("zhang")     //--->一般针对于包装类和基本数据类型
          private String name;
          @Value("男")
          private Integer age;
          @Value("男")
          private String sex;
          
          @Autowired()    //----> 对对象类型直接注入
          private Demo demo;
      }
      
  3. 依赖注入常用的注解:

    1. @Value():用于注入基本类型数据
    2. @Autowired():用于注入引用类型
    3. @Qualifier():和 @Autowired 一起使用,强制使用名称注入
    4. @Resource():一般不用( jdk 提供),按名称注入对象
    5. @Scope:声明周期注解
      1. singleton(默认值):单实例
      2. prototype:多例
  4. 初始化方法和销毁方法注解:

    1. @PostConstrust 相当于 init-method
    2. @PreDestroy 相当于 destroy-method
  5. 不用配置文件,用注解赋值方式:

    1. 实体类配置:

      @Configuration      //标明当前类为配置类
      @ComponentScan(value = "com.spring.service")    //扫描固定的包
      public class User {
          @Value("zhang")     //--->一般针对于包装类和基本数据类型
          private String name;
          @Value("18")
          private Integer age;
          @Value("男")
          private String sex;
      
          @Autowired()    //----> 对对象类型直接注入
          private Demo demo;
          
      }
      
    2. 测试类获取:

      public class Test {
          public static void main(String[] args) {
              ApplicationContext ac = new AnnotationConfigApplicationContext(User.class);
              User user = (User) ac.getBean("user");
              System.out.println(user.toString());
          }
      }
      

多配置文件形式:

  1. 在加载配置文件时,后多加自己需要的配置文件:
  2. 在一个配置文件中利用 <import resource = " " /> 引入另一个配置文件:

Spring 框架开发方式:

  1. 需求:编写 service 和 dao 的类
  2. 技术选择:持久层使用 JDBC 的程序,连接池是 Druild 连接池,创建 maven 工程,导入 jar 包
  3. 开发流程:
    1. 导入相关 jar 包:

      <dependencies>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>5.0.2.RELEASE</version>
          </dependency>
          <dependency>
              <groupId>commons-logging</groupId>
              <artifactId>commons-logging</artifactId>
              <version>1.2</version>
          </dependency>
          <dependency>
              <groupId>log4j</groupId>
              <artifactId>log4j</artifactId>
              <version>1.2.12</version>
          </dependency>
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.12</version>
              <scope>test</scope>
          </dependency>
          <!--连接池-->
          <dependency>
              <groupId>com.alibaba</groupId>
              <artifactId>druid</artifactId>
              <version>1.1.10</version>
          </dependency>
          <!--mysql驱动包-->
          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <version>5.1.6</version>
          </dependency>
      
      </dependencies>
      
    2. 创建数据库,创建表结构:

      create database spring_db;
      use spring_db;
      create table account(
          id int primary key auto_increment,
          name varchar(40),
          money double
      )character set utf8 collate utf8_general_ci;
      
      insert into account(name,money) values('aaa',1000);
      insert into account(name,money) values('bbb',1000);
      insert into account(name,money) values('ccc',1000);
      
    3. 编写 JavaBean 类:

      public class Account implements Serializable {
          public static final Long serialVersionUID = 7355810572012650248L;
      
          private Integer id;
          private String name;
          private Double money;
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public Double getMoney() {
              return money;
          }
      
          public void setMoney(Double money) {
              this.money = money;
          }
      
          @Override
          public String toString() {
              return "Account{" +
                      "id=" + id +
                      ", nane='" + name + '\'' +
                      ", money=" + money +
                      '}';
          }
      }
      
    4. 编写 AccountDao 接口实现类:

      public class AuccountDaoImpl implements AccountDao {
          //注入连接池对象
          private DataSource dataSource;
          public void setDataSource(DataSource dataSource){
              this.dataSource = dataSource;
          }
          /**
           * 查询所有的数据
           * @return
           */
          @Override
          public List<Account> finAll() {
              List<Account> list = new ArrayList<>();
      
      
              Connection connection = null;
              PreparedStatement stmt = null;
              ResultSet rs = null;
      
              try{
                  //获取链接
                  connection = dataSource.getConnection();
                  //编写 sql
                  String sql = "select * from account";
                  //预编译
                  stmt = connection.prepareStatement(sql);
                  //查询数据
                  rs = stmt.executeQuery();
                  //遍历结构集
                  while(rs.next()){
                      Account account = new Account();
                      account.setId(rs.getInt("id"));
                      account.setName(rs.getString("name"));
                      account.setMoney(rs.getDouble("money"));
                  }
              }catch (Exception e){
                  e.printStackTrace();
              }finally {
                  try{
                      connection.close();
                      stmt.close();
                      rs.close();
                  }catch (Exception e){
                      e.printStackTrace();
                  }
      
              }
      
              return list;
          }
      }
      
    5. 编写配置文件:

      <!--配置连接池-->
      <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
          <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
          <property name="url" value="jdbc:mysql:///spring_db"/>
          <property name="username" value="root"/>
          <property name="password" value="root"/>
      </bean>
      
      <!--管理Bean-->
      <bean id="accountService" class="com.spring.service.Impl.AccountServiceImpl">
          <property name="accountDao" ref="accountDao"/>
      </bean>
      <bean id="accountDao" class="com.spring.dao.Impl.AuccountDaoImpl">
          <property name="dataSource" ref="dataSource"/>
      </bean>
      
    6. 编写测试程序:

      public class Test {
          @org.junit.Test
          public void run(){
              ApplicationContext applicationContext = new ClassPathXmlApplicationContext("aaplication.xml");
              AccountService accountService = (AccountService) applicationContext.getBean("accountService");
              List<Account> list = accountService.findAll();
              for (Account account : list){
                  System.out.println(account);
              }
          }
      }
      

IOC纯注解方式:

  1. 概述:

    1. 纯注解方式是微服务架构开发的主要方式
    2. 替换掉所有的配置文件,但是需要写配置类
  2. 常用的注解:

    1. @Configuration:声明该类为配置类

    2. @ComponentScan:扫描具体包结构

    3. @Import:用于导入其他配置类

      //Spring 配置类,替换掉 applicationContext.xml
      //声明当前是配置类
      @Configuration
      //扫描指定的包结构
      @ComponentScan("com.qcby.spring")
      //导入其他配置类
      @Import(value = SpringConfig2.class)
      public class SpringConfig {
          
      }
      
      @Component
      public class SpringConfig2 {
      }
      
    4. @Bean:只能写在方法上,表明使用此方法创建一个对象,对象创建完成保存到 IOC 容器中

      @Bean(name="dataSource")
      public DataSource creatDataSource(){
          DruidDataSource dataSource = new DruidDataSource();
          dataSource.setDriverClassName("com.mysql.jdbc.Driver");
          dataSource.setUrl("jdbc:mysql:///community");
          dataSource.setUsername("root");
          dataSource.setPassword("root");
          return dataSource;
      }
      
  3. 案例:

    1. 编写实体类:

      @Component
      public class Order {
          @Value("北京")
          private String address;
      
          @Override
          public String toString() {
              return "Order{" +
                      "address='" + address + '\'' +
                      '}';
          }
      }
      
    2. 编写配置类:

      //Spring 配置类,替换掉 applicationContext.xml
      //声明当前是配置类
      @Configuration
      
      //扫描指定的包结构
      @ComponentScan("com.qcby.spring")
      public class SpringConfig {
          
      }
      
    3. 编写测试方法:

      @Test
      public void run1(){
          //创建工厂,加载配置类
          ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
      
          //获取对象
          Order order = (Order) ac.getBean("order");
          System.out.println(order);
      }
      

Spring 框架整合 JUnit 单元测试:

  1. 导入依赖:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.0.2.RELEASE</version>
        <scope>test</scope>
    </dependency>
    
  2. 配置文件形式:

    1. 编写类和方法,并把该类交给 IOC 容器进行管理:

      public class User {
      
          public void sayHello(){
              System.out.println("Hello");
          }
      }
      
    2. 编写配置文件:

      <?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="user" class="com.qcby.spring.pojo.User"></bean>
      
      </beans>
      
    3. 编写测试方法

      //Spring整合单测试
      @RunWith(value = SpringJUnit4ClassRunner.class)
      @ContextConfiguration(value = "classpath:application_test.xml")
      public class Demo {
      
          //自动注入
          @Autowired
          private User user;
      
          @Test
          public void run1(){
              user.sayHello();
          }
      }
      
  3. 纯注解方式整合单元测试:

    1. 编写类和方法:

      @Component
      public class Customer {
          public void save(){
              System.out.println("保存客户");
          }
      }
      
    2. 编写配置方法:

      //声明配置类
      @Configuration
      //扫描包
      @ComponentScan(value = "com.qcby.spring")
      public class SpringConfig3 {
          
      }
      
    3. 编写测试方法:

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(classes = SpringConfig3.class)
      public class Demo2 {
      
          //注入对象
          @Autowired
          private Customer customer;
      
          //测试
          @Test
          public void run(){
              customer.save();
          }
      }
      
相关推荐
以后不吃煲仔饭10 分钟前
Java基础夯实——2.7 线程上下文切换
java·开发语言
进阶的架构师11 分钟前
2024年Java面试题及答案整理(1000+面试题附答案解析)
java·开发语言
The_Ticker16 分钟前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
Elastic 中国社区官方博客23 分钟前
Elasticsearch 开放推理 API 增加了对 IBM watsonx.ai Slate 嵌入模型的支持
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
企鹅侠客27 分钟前
ETCD调优
数据库·etcd
Json_1817901448033 分钟前
电商拍立淘按图搜索API接口系列,文档说明参考
前端·数据库
大数据编程之光39 分钟前
Flink Standalone集群模式安装部署全攻略
java·大数据·开发语言·面试·flink
煎饼小狗1 小时前
Redis五大基本类型——Zset有序集合命令详解(命令用法详解+思维导图详解)
数据库·redis·缓存
爪哇学长1 小时前
双指针算法详解:原理、应用场景及代码示例
java·数据结构·算法
ExiFengs1 小时前
实际项目Java1.8流处理, Optional常见用法
java·开发语言·spring