Spring快速入门+进阶

Spring快速入门

​ 本文适合一定基础(了解MVC与三层架构),需要快速入手的开发人员阅读

​ 补充:MVC与三层架构关系图
在这里插入图片描述
r

1.1 简介
  • spring(春天):Spring框架是一个开放源代码J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。

    • 功能:使用基本的JavaBean代替EJB

    • 目的:解决企业应用开发的复杂性

    • 理念:是现有技术更加容易的使用,整合现有技术框架

    • Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于J2EE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。Spring框架主要由七部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。(百度百科)

  • 历史:2002年,首次出现spring的雏形:interface 21框架,2004年3月24号发布1.0正式版;以前学习SSH(Struct2 + Spring + Hibernate)和SSM(Spring+SpringMVC +Mybatis);

  • 官网:https://spring.io/ 快速开始:https://spring.io/quickstart

  • 依赖下载:https://mvnrepository.com/ 搜索spring,引入上述的7部分或者spring -web mvc

1.2 Spring使用优点
  • 是一个免费开源、轻量级、非侵入式(引入spring不会对之前的业务代码产生影响)的框架(容器)
  • 支持控制反转(IOC)、面向切面(AOP)编程
  • 支持事务处理、框架整合支持
1.3 Spring7大模块及功能
  1. Spring AOP:source-level metadata AOP infrastructure

  2. Spring ORM: Hibernate support 、iBats support、JDO support

  3. Spring Web: WebApplicationContext、Mutipart resolver、Web utlities

  4. Spring Dao:Transaction infrastructure、JDBC support、DAO support

  5. Spring Context:Application context、UI support、Validation、JNDL EJB support and rdemodeling Mail

  6. Spring Web Mvc:Web Mvc、Framework、Web Views、Jsp/Velocity、PDF/Export

  7. Spring Core:Supporting utlities、Bean container
    在这里插入图片描述

  8. 扩展

    • SpringBoot:一个快速开发的脚手架,在spring基础上,做了大量的自动配置(即约定大于配置);解决了spring发展后期的弊端(大量的配置甚至比开发麻烦)
    • SpringCloud:基于SpringBoot实现

在这里插入图片描述

1.4 理解IOC与AOP
  • IOC简介

    1. 控制反转:程序员不再管理对象的创建,只提供接口接受所需对象,从而专注于业务实现。例如:

      • 假设一业务结构如下:

      用户访问控制层代码:new UserServiceImpl().fun1();

      ​ |调用

      ​ |----> 业务层:UserService(private UserDao = new UserDaoImpl1/2/…();)

      ​ |调用

      ​ |—>DAO层:UserDao(UserDaoImpl1、UserDaoImpl2…)

      ​ 在这种结构下有以下情形:某公司在某一时期使用了一种数据库(MySql),而当过了某一时期后公司又换了另外一种数据库(Oracle)。这时候用户访问者如果想正常使用业务功能,就需要程序员根据数据库不同修改业务中的DAO实现类对象。

      ​ 老做法是:在业务层的实现类中使用组合的方式手动创建不同DAO对象,此时对象的创建掌握在程序员的手中。

      ​ 新做法是:在业务层中只提供一个DAO对象引用,之后利用在控制层创建的业务层对象的set方法,在程序运行时根据用户访问者提供的信息再选择创建何种DAO对象,此时对象的创建权在用户访问控制层者手里,他可以选择创建何种DAO对象。

      对比这两种方式根本性的变化在于控制权的变化!站在业务层的代码的角度来说,DAO对象的创建由主动创建(控制权在程序员手中)变成了被动接收。系统耦合性降低,程序架构不需要改变(spring底层原理)。

      • 业务模拟代码:

        目录结构:

        com.ioc.controller下UserController;用户访问控制层

        package com.ioc.controller;
        
        import com.ioc.dao.impl.UserDaoOracleImpl;
        import com.ioc.service.Impl.UserServiceImpl;
        
        public class UserController {
            public static void main(String[] args) {
                UserServiceImpl service = new UserServiceImpl();
                //1、老做法
                //service.getInfo();
                //2、新做法
                //service.setDao(new UserDaoOracleImpl());
                //service.getInfo();
            }
        }
        
        

        com.ioc.service下UserService 与com.ioc.service.impl下UserServiceImpl;业务层

        package com.ioc.service;
        
        public interface UserService {
            void getInfo();
        }
        

        老做法:

        package com.ioc.service.Impl;
        
        import com.ioc.dao.UserDao;
        import com.ioc.dao.impl.UserDaoMySqlImpl;
        import com.ioc.service.UserService;
        
        public class UserServiceImpl implements UserService {
            //1、公司使用mysql
            private UserDao dao = new UserDaoMySqlImpl();
        
            //2、公司改为oracle  此时需要修改代码
            //private UserDao dao = new UserDaoMySqlImpl();
            @Override
            public void getInfo() {
                dao.queryInfo();
            }
        }
        

        新做法:

        package com.ioc.service.Impl;
        
        import com.ioc.dao.UserDao;
        import com.ioc.dao.impl.UserDaoMySqlImpl;
        import com.ioc.service.UserService;
        
        public class UserServiceImpl implements UserService {
            //1、公司使用mysql
            //private UserDao dao = new UserDaoMySqlImpl();
        
            //2、公司改为oracle  此时需要修改代码
            //private UserDao dao = new UserDaoMySqlImpl();
            private UserDao dao;
        
            public void setDao(UserDao dao) {
                this.dao = dao;
            }
        
            @Override
            public void getInfo() {
                dao.queryInfo();
            }
        }
        

        com.ioc.dao下UserDao与com.ioc.dao.impl下UserDaoMySql/OracleImpl;DAO层

        package com.ioc.dao;
        
        public interface UserDao {
            void queryInfo();
        }
        
      package com.ioc.dao.impl;
      
      import com.ioc.dao.UserDao;
      
      public class UserDaoMySqlImpl implements UserDao {
          @Override
          public void queryInfo() {
              System.out.println("MySql");
          }
      }
      
      package com.ioc.dao.impl;
      
      import com.ioc.dao.UserDao;
      
      public class UserDaoOracleImpl implements UserDao {
          @Override
          public void queryInfo() {
              System.out.println("Oracle");
          }
      }
      
    2. 实现IOC的方式有很多种,xml、DI(依赖注入)等,新版的Spring可以配置实现IOC;程序需要的某一对象就可以从IOC容器中获取,不再由程序主动创建。

    3. 在spring中实现IOC的方式是IOC容器。

    4. Spring中的IOC容器干的事就是帮我们获取想要的对象,Spring项目启动,IOC容器在初始化的时候先读取配置文件,根据配置文件或元数据创建、组织对象并存入容器,程序使用时再从IOC容器中接收。

  • AOP简介

2.1 Spring使用
  • 快速创建一个Spring程序:

    1. 创建一个空的maven项目,导入spring依赖:

      <dependencies>
      <!--导入spring依赖 -->
      	<dependency>
      		<groupId>org.springframework</groupId>
      		<artifactId>spring-webmvc</artifactId>
      		<version>5.1.10.RELEASE</version>
      	</dependency>
      	<!--导入junit单元测试依赖-->
      	<dependency>
      		<groupId>junit</groupId>
      		<artifactId>junit</artifactId>
      		<version>4.13</version>
          	<scope>test</scope>
      	</dependency>
      </dependencies>
      
    2. 编写代码即可,例如以下一个实体类(必须要有get/set方法,否则无法正常使用):

      package com.demo.entity;
      
      public class User {
          private Integer userId;
          private String userName;
          private String userPwd;
      
          //非必要
          public User() {
          }
      
          //非必要
          public User(Integer userId, String userName, String userPwd) {
              this.userId = userId;
              this.userName = userName;
              this.userPwd = userPwd;
          }
      
          //除非必要外,全是必要。
          public Integer getUserId() {
              return userId;
          }
      
          public void setUserId(Integer userId) {
              this.userId = userId;
          }
      
          public String getUserName() {
              return userName;
          }
      
          public void setUserName(String userName) {
              this.userName = userName;
          }
      
          public String getUserPwd() {
              return userPwd;
          }
      
          public void setUserPwd(String userPwd) {
              this.userPwd = userPwd;
          }
      
          //非必要
          @Override
          public String toString() {
              return "User{" +
                      "userId=" + userId +
                      ", userName='" + userName + '\'' +
                      ", userPwd='" + userPwd + '\'' +
                      '}';
          }
      }
      
      
    3. 在resource目录下创建spring配置文件(spring-beans.xml),此时如果是使用idea开发工具会提醒你配置application context,一切默认即可(记住选中当前的maven项目就行了)

      <?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就是Java对象,控制权交给spring来管理 -->
          <bean id="user" class="com.demo.entity.User"></bean>
      </beans>
      
    4. 在test下创建测试类测试

      import com.demo.entity.User;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestUser {
          @Test
          public void testUser() {
              ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
              User user = (User)context.getBean("user");
              System.out.println(user == null);
              System.out.println(user);
          }
      }
      

      user对象不为null,该对象由spring创建,并托管到ioc容器。

    5. 扩展,利用xml中的bean标签对user对象赋值

      <?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就是Java对象,控制权交给spring来管理 -->
          <bean id="user" class="com.demo.entity.User">
              <property name="userId" value="1"/>
              <property name="userName" value="admin"/>
              <property name="userPwd" value="123"/>
          </bean>
      </beans>
      
      

      【思考】:对于对象的操作,需要改动我们的代码吗?不需要

      spring IOC:对象由Spring来创建、管理、装配

  • Spring基本类图

    在这里插入图片描述

    【了解】ApplicationContext和BeanFactory的区别:

    • 创建对象的时间不一致
    • ApplicationContext:读取配置文件时会创建所有对象
    • BeanFactory:功能单一,需要某个对象时才会创建对象,在资源匮乏时考虑使用
2.2 Spring基本配置
  1. bean标签

    • bean标签属性,控制创建的对象。

      属性名属性作用
      id对象的唯一标识
      name别名
      class类的全限定名
      scope对象的作用域
  2. import导入

    • 通过import标签可以导入其他配置文件,协同开发

      <import resource="{path}/xxx.xml"/>
      
  3. bean作用域

    • 规定每个创建的对象的生命周期和作用范围

      属性值值含义
      singleton单例 ,spring容器创建的对象都为同一对象
      prototype多例,每个对象都不一致
      request适用web项目中,request域中,对象一致
      session适用web项目,session域中,对象一致
    • 例:

      <bean id="user" name="u1" class="com.demo.entity.User" scope="singleton">
      
3.1 对象的创建和获取
  1. spring容器通过无参构造创建对象(即使是实体类中仍然有有参构造)

    • 测试:在上述实体类无参构造中添加以下代码

      public User() {
      	System.out.println("执行了User的无参构造方法");
      }
      

      结果:

      执行了User的无参构造方法
      false
      User{userId=1, userName='admin', userPwd='123'}
      
  2. 使用有参构造创建

    • public User(Integer userId, String userName, String userPwd) {
              this.userId = userId;
              this.userName = userName;
              this.userPwd = userPwd;
              System.out.println("执行了User的有参构造方法");
          }
      
    • 有三种方式赋值

      <bean id="user2" name="u2" class="com.demo.entity.User">
          <!--通过索引 下标从0开始,标识第一个参数
          <constructor-arg index="0" value="2"/>
          <constructor-arg index="1" value="li4"/>
          <constructor-arg index="2" value="123"/>-->
          <!--通过参数名字
          <constructor-arg name="id" value="2"/>
          <constructor-arg name="userName" value="li4"/>
          <constructor-arg name="password" value="123"/>-->
          <!--通过参数类型 下标从0开始,标识第一个参数-->
          <constructor-arg type="java.lang.Integer" value="2"/>
          <constructor-arg type="java.lang.String" value="lisa"/>
          <constructor-arg type="java.lang.String" value="123"/>
      </bean>
      
    • 结果

      执行了User的无参构造方法
      执行了User的有参构造方法
      false
      User{userId=2, userName='lisa', userPwd='123'}
      
  3. 对象获取的三种方式

    • 通过id或name获取

      ApplicationContext context = new
      ClassPathXmlApplicationContext("spring-beans.xml");
      	User u1 = (User)context.getBean("u1");
      	System.out.println(u1);
      
    • 通过类型获取,bean标签中可以不配置id

      ApplicationContext context = new
      ClassPathXmlApplicationContext("spring-beans.xml");
      	User user = context.getBean(User.class);
      	System.out.println(user);
      
    • 通过类型及id/name获取【推荐】

      ApplicationContext context = new
      ClassPathXmlApplicationContext("beans.xml");
      	User user = context.getBean(“u1”,User.class);
      	System.out.println(user);
      
4.1 依赖注入(DI)
4.2
  • 依赖注入(Dependency Injection)是spring的核心之一,是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建这个对象,而是依赖于外部的注入。Spring的依赖注入对调用者和被调用者几乎没有任何要求,完全支持对POJO之间依赖关系的管理。
  • 【思考】创建的Bean都是不带属性的!如果要创建的Bean需要一些预设的属性,怎么办?
  • 继续延续IOC的思想,如果需要属性依赖,交给spring容器,为你赋值!简单来说,就是不用在业务层去创建持久层的对象,而交给spring容器向业务层注入持久层对象。

在这里插入图片描述

4.2 两种注入方式
  • 通过构造方法注入

    • 【注意】实体类中必须有对应参数的构造方法,使用构造方法对属性进行赋值。

    • 例子:

      1. 创建实体类Person
      package com.demo2.entity;
      
      import java.util.Date;
      
      public class Person {
          private String name;
          private int age;
          private Date birthdayDate;
      
          public Person() {
          }
      
          public Person(String name, int age, Date birthdayDate) {
              this.name = name;
              this.age = age;
              this.birthdayDate = birthdayDate;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          public Date getBirthdayDate() {
              return birthdayDate;
          }
      
          public void setBirthdayDate(Date birthdayDate) {
              this.birthdayDate = birthdayDate;
          }
      
          @Override
          public String toString() {
              return "Person{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      ", birthdayDate=" + birthdayDate +
                      '}';
          }
      }
      
      1. 通过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使用ref
                   将Date对象注入到了Person对象中
                -->
            <bean id="birthday" class="java.util.Date"/>
        
            <bean id="person1" name="p1" class="com.demo2.entity.Person">
                <constructor-arg name="name" value="admin"/>
                <constructor-arg name="age" value="20"/>
                <constructor-arg name="birthdayDate" ref="birthday"/>
            </bean>
        </beans>
        
      2. 测试

        import com.demo2.entity.Person;
        import org.junit.Test;
        import org.springframework.context.ApplicationContext;
        import org.springframework.context.support.ClassPathXmlApplicationContext;
        
        public class TestPerson {
            @Test
            public void testPerson() {
                ApplicationContext context = new ClassPathXmlApplicationContext("demo2/person.xml");
                Person p1 = (Person) context.getBean("p1");
                System.out.println(p1);
            }
        }
        
        
      3. 结果

        Person{name='admin', age=20, birthdayDate=Wed Nov 16 13:28:03 CST 2022}
        
  • 通过get/set方法注入【重点】

    • 【注意】实体类中必须有set方法,适用set方法对属性赋值,且set方法必须是set+属性名第一个首字母变大写的方式。

      1. 修改Person类增加测试属性,并为属性增加set方法

        package com.demo2.entity;
        
        import java.util.*;
        
        public class Person {
            private String name;
            private int age;
            private Date birthdayDate;
            //set注入测试数据
            private String[] strings;
            private List<String> lists;
            private Set<String> sets;
            private Map<Integer,String> maps;
            private Properties props;
        
            public Person() {
            }
        
            public Person(String name, int age, Date birthdayDate, String[] strings, List<String> lists, 
                          Set<String> sets, Map<Integer, String> maps, Properties props) {
                this.name = name;
                this.age = age;
                this.birthdayDate = birthdayDate;
                this.strings = strings;
                this.lists = lists;
                this.sets = sets;
                this.maps = maps;
                this.props = props;
            }
        
            public String getName() {
                return name;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
            public int getAge() {
                return age;
            }
        
            public void setAge(int age) {
                this.age = age;
            }
        
            public Date getBirthdayDate() {
                return birthdayDate;
            }
        
            public void setBirthdayDate(Date birthdayDate) {
                this.birthdayDate = birthdayDate;
            }
        
            public String[] getStrings() {
                return strings;
            }
        
            public void setStrings(String[] strings) {
                this.strings = strings;
            }
        
            public List<String> getLists() {
                return lists;
            }
        
            public void setLists(List<String> lists) {
                this.lists = lists;
            }
        
            public Set<String> getSets() {
                return sets;
            }
        
            public void setSets(Set<String> sets) {
                this.sets = sets;
            }
        
            public Map<Integer, String> getMaps() {
                return maps;
            }
        
            public void setMaps(Map<Integer, String> maps) {
                this.maps = maps;
            }
        
            public Properties getProps() {
                return props;
            }
        
            public void setProps(Properties props) {
                this.props = props;
            }
        
            @Override
            public String toString() {
                return "Person{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        ", birthdayDate=" + birthdayDate +
                        ", strings=" + Arrays.toString(strings) +
                        ", lists=" + lists +
                        ", sets=" + sets +
                        ", maps=" + maps +
                        ", props=" + props +
                        '}';
            }
        }
        
        
      2. 不同类型的set注入方式

        	<bean id="birthday" class="java.util.Date"/>
            <!--如果引用其他bean使用ref,将Date对象注入到了Person对象中-->
        
        	<!--2、增加属性后使用set方法注入-->
            <bean  id="person1" name="p1" class="com.demo2.entity.Person">
                <!--2.1、常量注入-->
                <property name="name" value="admin"/>
                <property name="age" value="20"/>
                <!--2.2、bean注入-->
                <property name="birthdayDate" ref="birthday"/>
                <!--2.3、数组注入-->
                <property name="strings">
                    <array>
                        <value>a</value>
                        <value>b</value>
                        <value>c</value>
                    </array>
                </property>
                <!--2.4、List注入-->
                <property name="lists">
                    <list>
                        <value>La</value>
                        <value>Lb</value>
                        <value>Lc</value>
                    </list>
                </property>
                <!--2.5、set注入-->
                <property name="sets">
                    <set>
                        <value>Sa</value>
                        <value>Sb</value>
                        <value>Sc</value>
                    </set>
                </property>
                <!--2.5、map注入-->
                <property name="maps"><!--注意存放类型与定义类型一致-->
                    <map>
                        <entry key="1" value="a"></entry>
                        <entry key="2" value="b"></entry>
                        <entry key="3" value="c"></entry>
                    </map>
                </property>
                <!--2.6、properties注入-->
                <property name="props">
                    <props>
                        <prop key="身高">170cm</prop>
                        <prop key="体重">50kg</prop>
                    </props>
                </property>
            </bean>
        
        • 测试结果
        Person{name='admin', age=20, birthdayDate=Wed Nov 16 13:51:44 CST 2022, strings=[a, b, c], lists=[La, Lb, Lc], sets=[Sa, Sb, Sc], maps={1=a, 2=b, 3=c}, props={身高=170cm, 体重=50kg}}
        
      3. p注入和c注入

        需要在标签内导入约束:

        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:c="http://www.springframework.org/schema/c"
        
        • p空间注入

          <!-- p空间注入 等价于set注入 -->
          <bean id="person2" name="p2" class="com.demo2.entity.Person" p:name="zhang3"/>
          
        • c空间注入

          <!-- c空间注入 等价于构造方法注入 -->
          <bean id="person3" name="p3" class="com.demo2.entity.Person" c:name="li4" c:age="23"/>
          
          • 【注意】:实体类中必须提供对应参数的构造方法,否则会产生错误
5.1 自动装配
  • 概念:自动装配:spring会在应用(配置文件)的上下文中为某个组件寻找其依赖的bean。对比注入,只需要写好bean标签即可,不需要手动注入。

  • 本质:

    • 组件扫描(component scanning): spring会自动发现配置文件上下文中所创建的bean。

    • 自动装配(autowiring):spring会自动装配满足bean之间的依赖关系。

    • 例子:人(People)将纸币(Notes)装入钱包(Wallet)

      People类

      package com.demo3;
      
      public class People {
          private String name;
          private Notes notes;
          private Wallet wallet;
      
          public People() {
          }
      
          public People(String name, Notes notes, Wallet wallet) {
              this.name = name;
              this.notes = notes;
              this.wallet = wallet;
          }
      
          public void show() {
              System.out.println(name + "把"+ notes + "装入" + wallet);
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public Notes getNotes() {
              return notes;
          }
      
          public void setNotes(Notes notes) {
              this.notes = notes;
          }
      
          public Wallet getWallet() {
              return wallet;
          }
      
          public void setWallet(Wallet wallet) {
              this.wallet = wallet;
          }
      }
      
      

      Notes类

      package com.demo3;
      
      public class Notes {
          //金额
          private Integer num;
      
          public Notes() {
          }
      
          public Notes(Integer num) {
              this.num = num;
          }
      
          public Integer getNum() {
              return num;
          }
      
          public void setNum(Integer num) {
              this.num = num;
          }
      
          @Override
          public String toString() {
              return "Notes{" +
                      "num=" + num +
                      '}';
          }
      }
      
      

      Wallet类

      package com.demo3;
      
      public class Wallet {
          //谁的钱包:比如我的钱包(即name="我")
          private String name;
      
          public Wallet() {
          }
      
          public Wallet(String name) {
              this.name = name;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          @Override
          public String toString() {
              return "Wallet{" +
                      "name='" + name + '\'' +
                      '}';
          }
      }
      
      
5.1 手动装配演示(为了方便理解先展示手动装配:本质上其实就是上面我们一个一个注入属性)
  • 测试:
import com.demo3.People;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestDemo3 {
    @Test
    public void testDemo3() {
        ApplicationContext context= new ClassPathXmlApplicationContext("demo3/demo3-beans.xml");
        People people = context.getBean(People.class);
        people.show();
    }
}

  • 配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="notes1" class="com.demo3.Notes">
            <property name="num" value="100"/>
        </bean>
    
        <bean id="people" class="com.demo3.People">
            <property name="name" value=""/>
            <property name="notes" ref="notes1"/>
            <property name="wallet" ref="wallet1"/>
        </bean>
    
        <bean id="wallet1" class="com.demo3.Wallet" p:name="我的钱包"/>
    </beans>
    
  • 结果:

我把Notes{num=100}装入Wallet{name='我的钱包'}
5.2 自动装配(两种实现方式)
  1. byName方式:通过名称自动装配

     <!--byName-->
    <bean id="notes1" name="notes" class="com.demo3.Notes">
            <property name="num" value="100"/>
    </bean>
    <bean id="wallet1" name="wallet" class="com.demo3.Wallet" p:name="我的钱包"/>
    <bean id="people1" class="com.demo3.People" autowire="byName">
         <property name="name" value=""/>
    </bean>
    

    结果:

    我把Notes{num=100}装入Wallet{name='我的钱包'}
    

    原理:

    • 查找实体类中属性set方法
    • 将set方法拆分为set+属性,将属性首字母变小写得到字符串
    • 根据字符串寻找spring容器中的id(或者别名)
    • 如果有则装配,如果没有则为null
  2. byType方式:通过类型自动装配

 <!--byType-->
    <bean id="notes1" name="notes" class="com.demo3.Notes">
        <property name="num" value="100"/>
    </bean>
    <bean id="wallet1" name="wallet" class="com.demo3.Wallet" p:name="我的钱包"/>
    <bean id="people1" class="com.demo3.People" autowire="byType">
        <property name="name" value=""/>
    </bean>

【注意】:通过类型装配,必须保证spring容器中的类型是唯一的,如果不唯一则会报

NoUniqueBeanDefinitionException

5.3 通过注解实现自动装配
  1. 环境支持:jdk>=1.5,spring>=2.5

  2. 实现步骤:

    1. 配置文件中加入约束

      <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:p="http://www.springframework.org/schema/p"
      xmlns:c="http://www.springframework.org/schema/c"
      xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd">
      
    2. context标签开启注解支持

      <context:annotation-config/>
      
  3. 注解使用

    • @Autowired:Autowired是按照类型进行装配的,不支持id匹配

      <context:annotation-config/>
          <bean id="notes1" name="notes" class="com.demo3.Notes">
              <property name="num" value="100"/>
          </bean>
          <bean id="wallet1" name="wallet" class="com.demo3.Wallet" p:name="我的钱包"/>
          <bean id="people1" class="com.demo3.People">
              <property name="name" value=""/>
          </bean>
      
      • 在案例基础上修改实例体people,删除set方法,使用注解
      package com.demo3;
      
      import org.springframework.beans.factory.annotation.Autowired;
      
      public class People {
          private String name;
      
          @Autowired
          private Notes notes;
      
          @Autowired
          private Wallet wallet;
      
          public People() {
          }
      
          public People(String name, Notes notes, Wallet wallet) {
              this.name = name;
              this.notes = notes;
              this.wallet = wallet;
          }
      
          public void show() {
              System.out.println(name + "把"+ notes + "装入" + wallet);
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
      }
      
      • @Autowired(required=false) false:被装配对象可以为null true:对象不能为null
    • @Qualifier

      @Qualifier和@Autowired配合使用可以选择id自动装配【推荐】

      注意:@Qualifier不能单独使用

      • 修改配置文件

            <context:annotation-config/>
            <bean id="notes1" class="com.demo3.Notes">
                <property name="num" value="100"/>
            </bean>
            <bean id="notes2" class="com.demo3.Notes">
                <property name="num" value="200"/>
            </bean>
            <bean id="wallet1" class="com.demo3.Wallet" p:name="我的钱包"/>
            <bean id="wallet2" class="com.demo3.Wallet" p:name="我盆友的钱包"/>
            <bean id="people1" class="com.demo3.People">
                <property name="name" value=""/>
            </bean>
        
      • package com.demo3;
        
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.beans.factory.annotation.Qualifier;
        
        public class People {
            private String name;
        
            @Autowired(required = false)
            @Qualifier(value = "notes2")
            private Notes notes;
        
            @Autowired(required = false)
            @Qualifier(value = "wallet2")
            private Wallet wallet;
        
            public People() {
            }
        
            public People(String name, Notes notes, Wallet wallet) {
                this.name = name;
                this.notes = notes;
                this.wallet = wallet;
            }
        
            public void show() {
                System.out.println(name + "把"+ notes + "装入" + wallet);
            }
        
            public String getName() {
                return name;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
        }
        
      • 修改实体类测试

        package com.demo3;
        
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.beans.factory.annotation.Qualifier;
        
        public class People {
            private String name;
        
            @Autowired(required = false)
            @Qualifier(value = "notes2")
            private Notes notes;
        
            @Autowired(required = false)
            @Qualifier(value = "wallet2")
            private Wallet wallet;
        
            public People() {
            }
        
            public People(String name, Notes notes, Wallet wallet) {
                this.name = name;
                this.notes = notes;
                this.wallet = wallet;
            }
        
            public void show() {
                System.out.println(name + "把"+ notes + "装入" + wallet);
            }
        
            public String getName() {
                return name;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
        }
        
        
    • @Resource:如果指定name属性则先按照name或者id自动装配,如果失败,则继续按照byType属性装配。

      • 修改测试类

        package com.demo3;
        
        import org.springframework.beans.factory.annotation.*;
        
        import javax.annotation.Resource;
        
        public class People {
            private String name;
        
            /*@Autowired(required = false)
            @Qualifier(value = "notes2")*/
            @Resource(name = "notes1")
            private Notes notes;
        
            /*@Autowired(required = false)
            @Qualifier(value = "wallet2")*/
            @Resource(name = "wallet1")
            private Wallet wallet;
        
            public People() {
            }
        
            public People(String name, Notes notes, Wallet wallet) {
                this.name = name;
                this.notes = notes;
                this.wallet = wallet;
            }
        
            public void show() {
                System.out.println(name + "把"+ notes + "装入" + wallet);
            }
        
            public String getName() {
                return name;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
           
        }
        
        
5.3 基于注解开发
  • 在5.2注解自动装配的基础上,利用spring进行注解开发

  • 环境:必须有spring-aop包的支持;必须引入context约束;

  • 步骤:

    1. 创建实体类 student

      package com.demo4.entity;
      
      public class Student {
          private Integer id;
          private String studentName;
          private Double studentNumber;
      
          public Student() {
          }
      
          public Student(Integer id, String studentName, Double studentNumber) {
              this.id = id;
              this.studentName = studentName;
              this.studentNumber = studentNumber;
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getStudentName() {
              return studentName;
          }
      
          public void setStudentName(String studentName) {
              this.studentName = studentName;
          }
      
          public Double getStudentNumber() {
              return studentNumber;
          }
      
          public void setStudentNumber(Double studentNumber) {
              this.studentNumber = studentNumber;
          }
      
          @Override
          public String toString() {
              return "Student{" +
                      "id=" + id +
                      ", studentName='" + studentName + '\'' +
                      ", studentNumber=" + studentNumber +
                      '}';
          }
      }
      
      
    2. 配置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"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd">
          <!-- 开启注解支持 指定要扫描的包 -->
          <context:component-scan base-package="com.demo4.entity"/>
      </beans>
      
    3. 使用bean的管理注解(对比之前,现在不需要在xml中配置bean标签对bean对象进行操作)

      • @Component:作用于类上,等价于在spring容器中注册bean

        student类:

        //只截取了部分代码,其余代码与上面一致
        @Component
        public class Student {
            private Integer id;
            private String studentName;
            private Double studentNumber;
        

        测试

        import com.demo4.entity.Student;
        import org.junit.Test;
        import org.springframework.context.ApplicationContext;
        import org.springframework.context.support.ClassPathXmlApplicationContext;
        
        public class TestDemo4 {
            @Test
            public void testDemo4() {
                ApplicationContext context = new ClassPathXmlApplicationContext("demo4/demo4-beans.xml");
                Student student = (Student) context.getBean("student");
                Student student1 = (Student) context.getBean(Student.class);
                System.out.println(student);
                System.out.println(student == student1);
            }
        }
        
        

        结果:

        Student{id=null, studentName='null', studentNumber=null}
        true
        

        属性

        @Component(value="s1")//表示在spring容器中注册了bean id为s1, 如果不指定value则默认为类名首字母变小写student
        public class Student {
        

        衍生注解

        1. 为了更加突出的分层开发,@Component注解提供了3个衍生注解,作用一致

          @Repository:dao层

          @Service:service层

          @Controller:controller层

      • @Value:赋值注解,作用于属性或set方法之上

        @Value("zhang3")
        private String studentName;
        
        
        @Value("2014162023")
        public void setStudentNumber(Double studentNumber) {
        	this.studentNumber = studentNumber;
        }
        
      • @Scope:等价于bean标签的scope属性

        @Component(value = "student")
        @Scope("singleton")//管理spring容器中bean的作用范围
        public class Student {
        

        【注】不用刻意考虑其优缺点,两种bean管理方式都掌握,使用时根据场景选择便捷的方式即可。

      • 自动装配注解(详细在5.4中)

5.4 配置类
  • 【思考】:能不能完全脱离xml文件,使所有配置都使用注解实现呢?

  • 有,就是接下来讲的配置类(每一个配置类就相当于一个xml文件)

  • 使用步骤:

    1. 创建实体类

      package com.demo5.entity;
      
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.stereotype.Component;
      
      public class User {
          private Integer id;
          @Value("admin")
          private String userName;
          private String userPwd;
      
          public User() {
          }
      
          public User(Integer id, String userName, String userPwd) {
              this.id = id;
              this.userName = userName;
              this.userPwd = userPwd;
          }
      
          public Integer getId() {
              return id;
          }
      
          @Value("1")
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getUserName() {
              return userName;
          }
      
          public void setUserName(String userName) {
              this.userName = userName;
          }
      
          public String getUserPwd() {
              return userPwd;
          }
      
          public void setUserPwd(String userPwd) {
              this.userPwd = userPwd;
          }
      
          @Override
          public String toString() {
              return "User{" +
                      "id=" + id +
                      ", userName='" + userName + '\'' +
                      ", userPwd='" + userPwd + '\'' +
                      '}';
          }
      }
      
      
    2. 利用**@Configuration注解**创建配置类

    package com.demo5.config;
    
    import com.demo5.entity.User;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    @Configuration//表示当前MySpringConfigration是一个配置类
    public class MySpringConfigration {
        @Bean//该注解只能写在方法之上,表明使用此方法创建一个对象,并放入spring容器中
        public User user() {
            return new User();
        }
    }
    
    1. 测试

      import com.demo5.entity.User;
      import com.demo5.config.MySpringConfigration;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      
      public class TestDemo5 {
          @Test
          public void testDemo5() {
              ApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfigration.class);
              User user = context.getBean(User.class);
              System.out.println(user);
          }
      }
      
      

      结果:

      User{id=1, userName='admin', userPwd='null'}
      
  • 其他注解:

    • @ComponentScan用于指定在初始化容器时要扫描的包

      @Configuration//配置类
      @ComponentScan("com.hqyj.entity")
      public class MySpringConfigration {
      
    • @Bean 注册bean

      @Bean(name = "user1")//name属性指定bean的id
      public User user() {
      	return new User();
      }
      
    • @PropertySource 加载配置文件中的配置

    • @Value 获取配置文件中的值

      @Configuration//配置类
      @ComponentScan("com.demo5.entity")
      @PropertySource("classpath:demo.properties")//指定配置文件所在位置
      public class MySpringConfigration {
      	@Value("${jdbc.username}")//获取配置文件中的值
      	private String username;
          
      	@Bean(name = "u1")
      	public User user() {
      		User u = new User();
      		u.setUserName(username);
      		return u;
      	}
          
      }
      

      demo.properties:

      jdbc.username=zhang3
      
    • @import 导入其他配置类

      @Configuration
      @Import(JDBCConfig.class) //导入合并其他配置类
      public class MySpringConfigration {
      
6. spring整合Junit
  1. 导入依赖

    <dependency>
    	<groupId>junit</groupId>
    	<artifactId>junit</artifactId>
    	<version>4.13</version>
    	<scope>test</scope>
    </dependency>
    <dependency>
    	<groupId>org.springframework</groupId>
    	<artifactId>spring-test</artifactId>
    	<version>5.0.2.RELEASE</version>
    </dependency>
    
  2. 创建测试类

    import com.hqyj.configration.MySpringConfigration;
    import com.hqyj.entity.User;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import
    org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    /*-----------------------------------------------*/
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:beans.xml"})
    //@ContextConfiguration(classes = MySpringConfiguration.class)
    public class TestSpringConfigration {
    	@Autowired
    	public User user;
        
    	@Test
    	public void testUser() {
    		System.out.println(user);
    	}
    }
    
    • @Runwith 将Junit原有的运行器替换成spring提供的SpringJUnit4ClassRunner。这个注解的值就是运行器的字节码文件。

    • @ContextConfiguration 可以通过该属性手工指定 Spring 配置文件所在的位置,可以指定一个或多个 Spring 配置文件,并加载。

      @ContextConfiguration(locations={"classpath:applicationContextmapper.xml","classpath:applicationContext-service.xml"})
      @ContextConfiguration(locations="classpath*:applicationContext-*.xml")
      
    • locations:指定xml文件位置

    • classes:指定配置类的位置

4.13 test org.springframework spring-test 5.0.2.RELEASE ```
  1. 创建测试类

    import com.hqyj.configration.MySpringConfigration;
    import com.hqyj.entity.User;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import
    org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    /*-----------------------------------------------*/
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:beans.xml"})
    //@ContextConfiguration(classes = MySpringConfiguration.class)
    public class TestSpringConfigration {
    	@Autowired
    	public User user;
        
    	@Test
    	public void testUser() {
    		System.out.println(user);
    	}
    }
    
    • @Runwith 将Junit原有的运行器替换成spring提供的SpringJUnit4ClassRunner。这个注解的值就是运行器的字节码文件。

    • @ContextConfiguration 可以通过该属性手工指定 Spring 配置文件所在的位置,可以指定一个或多个 Spring 配置文件,并加载。

      @ContextConfiguration(locations={"classpath:applicationContextmapper.xml","classpath:applicationContext-service.xml"})
      @ContextConfiguration(locations="classpath*:applicationContext-*.xml")
      
    • locations:指定xml文件位置

    • classes:指定配置类的位置

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值