SSM-Spring框架学习

  1. 1. SSM-Spring框架学习
    1. 1.1. 一、概念
    2. 1.2. 二、优点
    3. 1.3. 三、组成
      1. 1.3.1. 3.1 Spring 框架是一个分层架构
      2. 1.3.2. 3.2 组成 Spring 框架的每个模块(或组件)都可以单独存在:
    4. 1.4. 四、控制反转(IOC)
      1. 1.4.1. 4.1 本质
    5. 1.5. 五、快速上手Spring
      1. 1.5.1. 5.1 配置环境
      2. 1.5.2. 5.2 编写代码
      3. 1.5.3. 5.3 IOC创建对象方式
        1. 1.5.3.1. 5.3.1 通过无参构造方法来创建
        2. 1.5.3.2. 5.3.2 通过有参构造方法来创建
    6. 1.6. 六、Spring配置
      1. 1.6.1. 6.1 别名
      2. 1.6.2. 6.2 Bean的配置
      3. 1.6.3. 6.3 import
    7. 1.7. 七、依赖注入(DI)
      1. 1.7.1. 7.1 概念
      2. 1.7.2. 7.2 Set注入
        1. 1.7.2.1. 7.2.1 常量注入
        2. 1.7.2.2. 7.2.2 Bean注入
        3. 1.7.2.3. 7.2.3 数组注入
        4. 1.7.2.4. 7.2.4 List注入
        5. 1.7.2.5. 7.2.5 Map注入
        6. 1.7.2.6. 7.2.6 set注入
        7. 1.7.2.7. 7.2.7 Null注入
        8. 1.7.2.8. 7.2.8 Properties注入
      3. 1.7.3. 7.3 p命名和c命名注入
        1. 1.7.3.1. 7.3.1 P命名空间注入 : 需要在头文件中加入约束文件
        2. 1.7.3.2. 7.3.2 c 命名空间注入 : 需要在头文件中加入约束文件
      4. 1.7.4. 7.4 Bean的作用域
        1. 1.7.4.1. 7.4.1 Singleton
        2. 1.7.4.2. 7.4.2 Prototype
          1. 1.7.4.2.1. 补充:scope中单例(singleton)和prototype的优缺点:
        3. 1.7.4.3. 7.4.3 Request
        4. 1.7.4.4. 7.4.3 Session
    8. 1.8. 八、自动装配
      1. 1.8.1. 8.1 概念
      2. 1.8.2. 8.2 装配机制
      3. 1.8.3. 8.3 实现
        1. 1.8.3.1. 8.3.1 autowire byName (按名称自动装配)
        2. 1.8.3.2. 8.3.2 autowire byType (按类型自动装配)
    9. 1.9. 九、使用注解
      1. 1.9.1. 9.1 配置
      2. 1.9.2. 9.2 @Autowired
      3. 1.9.3. 9.3 @Qualifier
      4. 1.9.4. 9.4 @Resource
      5. 1.9.5. 9.5 @Nullable <补充>
      6. 1.9.6. 小结
    10. 1.10. 十、使用注解开发
      1. 1.10.1. 10.1 配置
      2. 1.10.2. 10.2 bean的实现
      3. 1.10.3. 10.3 属性注入
      4. 1.10.4. 10.4 衍生注解
      5. 1.10.5. 10.5 作用域
      6. 1.10.6. 小结:
      7. 1.10.7. 10.6 基于Java类进行配置

SSM-Spring框架学习

一、概念

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

二、优点

1、Spring是一个开源免费的框架 , 容器 .

2、Spring是一个轻量级的框架 , 非侵入式的 .

3、控制反转 IoC , 面向切面 Aop

4、对事物的支持 , 对框架的支持

三、组成

3.1 Spring 框架是一个分层架构

​ 由 7 个定义良好的模块组成,Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 .

图片

3.2 组成 Spring 框架的每个模块(或组件)都可以单独存在:

  • 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
  • Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
  • Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
  • Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
  • Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
  • Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
  • Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

图片

拓展

Spring Boot与Spring Cloud

  • Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务;
  • Spring Cloud是基于Spring Boot实现的;
  • Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;
  • Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置 , Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。
  • SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。

四、控制反转(IOC)

4.1 本质

  • 控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法

  • 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)

  • IoC是Spring框架的核心内容

    ​ Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。<**在配置文件加载的时候,容器中管理的对象就已经初始化了**>

    图片

​ 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

五、快速上手Spring

5.1 配置环境

导入Jar包

​ 注 : spring 需要导入commons-logging进行日志记录 . 我们利用maven , 他会自动下载对应的依赖项 (包含测试依赖).

1
2
3
4
5
6
7
8
9
10
11
12
13
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>

5.2 编写代码

​ 1、编写一个Hello实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Hello {
private String name;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

public void show(){
System.out.println("Hello,"+ name );
}
}

​ 2、编写我们的spring文件 , 这里我们命名为beans.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?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="hello" class="com.kuang.pojo.Hello">
<property name="name" value="Spring"/>
</bean>

</beans>

​ 3、我们可以去进行测试了 .

1
2
3
4
5
6
7
8
@Test
public void test(){
//解析beans.xml文件 , 生成管理相应的Bean对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//getBean : 参数即为spring配置文件中bean的id .
Hello hello = (Hello) context.getBean("hello");
hello.show();
}

思考

  • Hello 对象是谁创建的 ? 【hello 对象是由Spring创建的
  • Hello 对象的属性是怎么设置的 ? hello 对象的属性是由Spring容器设置的

这个过程就叫控制反转 :

  • 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
  • 反转 : 程序本身不创建对象 , 而变成被动的接收对象 .

依赖注入 : 就是利用set方法来进行注入的.

IOC是一种编程思想,由主动的编程变成被动的接收

可以通过newClassPathXmlApplicationContext去浏览一下底层源码 .

5.3 IOC创建对象方式

5.3.1 通过无参构造方法来创建

1、User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class User {

private String name;

public User() {
System.out.println("user无参构造方法");
}

public void setName(String name) {
this.name = name;
}

public void show(){
System.out.println("name="+ name );
}

}

2、beans.xml

1
2
3
4
5
6
7
8
9
10
11
<?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.kuang.pojo.User">
<property name="name" value="kuangshen"/>
</bean>

</beans>

3、测试类

1
2
3
4
5
6
7
8
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//在执行getBean的时候, user已经创建好了 , 通过无参构造
User user = (User) context.getBean("user");
//调用对象的方法 .
user.show();
}

结果可以发现,在调用show方法之前,User对象已经通过无参构造初始化了!

5.3.2 通过有参构造方法来创建

1、UserT . java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class UserT {

private String name;

public UserT(String name) {
this.name = name;
}

public void setName(String name) {
this.name = name;
}

public void show(){
System.out.println("name="+ name );
}

}

2、beans.xml 有三种方式编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 第一种根据index参数下标设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<!-- index指构造方法 , 下标从0开始 -->
<constructor-arg index="0" value="kuangshen2"/>
</bean>
<!-- 第二种根据参数名字设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<!-- name指参数名 -->
<constructor-arg name="name" value="kuangshen2"/>
</bean>
<!-- 第三种根据参数类型设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<constructor-arg type="java.lang.String" value="kuangshen2"/>
</bean>

3、测试

1
2
3
4
5
6
@Test
public void testT(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserT user = (UserT) context.getBean("userT");
user.show();
}

结论:在配置文件加载的时候。其中管理的对象都已经初始化了!

六、Spring配置

6.1 别名

alias 设置别名 , 为bean设置别名 , 可以设置多个别名

1
2
<!--设置别名:在获取Bean的时候可以使用别名获取-->
<alias name="userT" alias="userNew"/>

6.2 Bean的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--bean就是java对象,由Spring创建和管理-->

<!--
id 是bean的标识符,要唯一,如果没有配置id,name就是默认标识符
如果配置id,又配置了name,那么name是别名
name可以设置多个别名,可以用逗号,分号,空格隔开
如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象;

class是bean的全限定名=包名+类名
-->
<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello">
<property name="name" value="Spring"/>
</bean>

6.3 import

团队的合作通过import来实现 .

1
<import resource="{path}/beans.xml"/>

七、依赖注入(DI)

7.1 概念

  • 依赖注入(Dependency Injection,DI)。
  • 依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 .
  • 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 .

7.2 Set注入

​ 要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is .

测试pojo类 :

Address.java

1
2
3
4
5
6
7
8
9
10
11
12
public class Address {

private String address;

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}
}

Student.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package com.kuang.pojo;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class Student {

private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;

public void setName(String name) {
this.name = name;
}

public void setAddress(Address address) {
this.address = address;
}

public void setBooks(String[] books) {
this.books = books;
}

public void setHobbys(List<String> hobbys) {
this.hobbys = hobbys;
}

public void setCard(Map<String, String> card) {
this.card = card;
}

public void setGames(Set<String> games) {
this.games = games;
}

public void setWife(String wife) {
this.wife = wife;
}

public void setInfo(Properties info) {
this.info = info;
}

public void show(){
System.out.println("name="+ name
+ ",address="+ address.getAddress()
+ ",books="
);
for (String book:books){
System.out.print("<<"+book+">>\t");
}
System.out.println("\n爱好:"+hobbys);

System.out.println("card:"+card);

System.out.println("games:"+games);

System.out.println("wife:"+wife);

System.out.println("info:"+info);

}
}

7.2.1 常量注入

1
2
3
<bean id="student" class="com.kuang.pojo.Student">
<property name="name" value="小明"/>
</bean>

测试:

1
2
3
4
5
6
7
8
9
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

Student student = (Student) context.getBean("student");

System.out.println(student.getName());

}

7.2.2 Bean注入

注意点:这里的值是一个引用,ref

1
2
3
4
5
6
7
8
<bean id="addr" class="com.kuang.pojo.Address">
<property name="address" value="重庆"/>
</bean>

<bean id="student" class="com.kuang.pojo.Student">
<property name="name" value="小明"/>
<property name="address" ref="addr"/>
</bean>

7.2.3 数组注入

1
2
3
4
5
6
7
8
9
10
11
<bean id="student" class="com.kuang.pojo.Student">
<property name="name" value="小明"/>
<property name="address" ref="addr"/>
<property name="books">
<array>
<value>西游记</value>
<value>红楼梦</value>
<value>水浒传</value>
</array>
</property>
</bean>

7.2.4 List注入

1
2
3
4
5
6
7
<property name="hobbys">
<list>
<value>听歌</value>
<value>看电影</value>
<value>爬山</value>
</list>
</property>

7.2.5 Map注入

1
2
3
4
5
6
<property name="card">
<map>
<entry key="中国邮政" value="456456456465456"/>
<entry key="建设" value="1456682255511"/>
</map>
</property>

7.2.6 set注入

1
2
3
4
5
6
7
<property name="games">
<set>
<value>LOL</value>
<value>BOB</value>
<value>COC</value>
</set>
</property>

7.2.7 Null注入

1
<property name="wife"><null/></property>

7.2.8 Properties注入

1
2
3
4
5
6
7
<property name="info">
<props>
<prop key="学号">20190604</prop>
<prop key="性别">男</prop>
<prop key="姓名">小明</prop>
</props>
</property>

扩展:Properties和Map都是以键值对的形式存储的,但是他们有什么区别吗?

​ 最大的区别就是 Properties可以直接导入IO流 读取IO流中的数据 并且能把自己的元素输出到IO流中。就是我们可以去写properties文件,进行读写。

7.3 p命名和c命名注入

7.3.1 P命名空间注入 : 需要在头文件中加入约束文件

1
2
3
4
导入约束 : xmlns:p="http://www.springframework.org/schema/p"

<!--P(属性: properties)命名空间 , 属性依然要设置set方法-->
<bean id="user" class="com.kuang.pojo.User" p:name="狂神" p:age="18"/>

7.3.2 c 命名空间注入 : 需要在头文件中加入约束文件

1
2
3
导入约束 : xmlns:c="http://www.springframework.org/schema/c"
<!--C(构造: Constructor)命名空间 , 属性依然要设置set方法-->
<bean id="user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>

7.4 Bean的作用域

​ 在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象 .

图片

7.4.1 Singleton

​ 当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。

1
<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">

7.4.2 Prototype

​ 当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。

1
2
3
<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>  
或者
<bean id="account" class="com.foo.DefaultAccount" singleton="false"/>

对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域

补充:scope中单例(singleton)和prototype的优缺点:

​ singleton(默认):优点:不会new对象,节省资源;缺点:在处理高并发的时候可能会延迟或数据不一致
​ prototype:优点:多线程稳定 缺点:每次在创建浪费资源
多线程使用prototype,单线程使用singleton

7.4.3 Request

​ 当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例。即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。

​ 针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效。当处理请求结束,request作用域的bean实例将被销毁。

1
<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>

7.4.3 Session

​ 当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。

1
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

​ 针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效.

八、自动装配

8.1 概念

  • 自动装配是使用spring满足bean依赖的一种方法
  • spring会在应用上下文中为某个bean寻找其依赖的bean。

8.2 装配机制

Spring中bean有三种装配机制,分别是:

  1. 在xml中显式配置;
  2. 在java中显式配置;
  3. 隐式的bean发现机制和自动装配。

8.3 实现

Spring的自动装配需要从两个角度来实现,或者说是两个操作:

  1. 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
  2. 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;

1、新建一个项目

2、新建两个实体类,Cat Dog 都有一个叫的方法

1
2
3
4
5
6
7
8
9
10
public class Cat {
public void shout() {
System.out.println("miao~");
}
}
public class Dog {
public void shout() {
System.out.println("wang~");
}
}

3、新建一个用户类 User

1
2
3
4
5
public class User {
private Cat cat;
private Dog dog;
private String str;
}

4、编写Spring配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>

<bean id="user" class="com.kuang.pojo.User">
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
<property name="str" value="qinjiang"/>
</bean>
</beans>

5、测试

1
2
3
4
5
6
7
8
9
public class MyTest {
@Test
public void testMethodAutowire() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
user.getCat().shout();
user.getDog().shout();
}
}

8.3.1 autowire byName (按名称自动装配)

​ 由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。

​ 采用自动装配将避免这些错误,并且使配置简单化。

测试:

​ 1、修改bean配置,增加一个属性 autowire=”byName”

1
2
3
<bean id="user" class="com.kuang.pojo.User" autowire="byName">
<property name="str" value="qinjiang"/>
</bean>

​ 2、再次测试,结果依旧成功输出!

​ 3、我们将 cat 的bean id修改为 catXXX

​ 4、再次测试, 执行时报空指针java.lang.NullPointerException。因为按byName规则找不对应set方法,真正的setCat就没执行,对象就没有初始化,所以调用时就会报空指针错误。

小结:

当一个bean节点带有 autowire byName的属性时。

  1. 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。
  2. 去spring容器中寻找是否有此字符串名称id的对象。
  3. 如果有,就取出注入;如果没有,就报空指针异常。

8.3.2 autowire byType (按类型自动装配)

使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。NoUniqueBeanDefinitionException

测试:

1、将user的bean配置修改一下 : autowire=”byType”

2、测试,正常输出

3、在注册一个cat 的bean对象!

1
2
3
4
5
6
7
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>

<bean id="user" class="com.kuang.pojo.User" autowire="byType">
<property name="str" value="qinjiang"/>
</bean>

4、测试,报错:NoUniqueBeanDefinitionException

5、删掉cat2,将cat的bean名称改掉!测试!因为是按类型装配,所以并不会报异常,也不影响最后的结果。甚至将id属性去掉,也不影响结果。

九、使用注解

9.1 配置

jdk1.5开始支持注解,spring2.5开始全面支持注解。

准备工作:利用注解的方式注入属性。

1、在spring配置文件中引入context文件头

1
2
3
4
xmlns:context="http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd

2、开启属性注解支持!

1
<context:annotation-config/>

9.2 @Autowired

  • @Autowired是按类型自动转配的,不支持id匹配。
  • 需要导入 spring-aop的包!

测试:

1、将User类中的set方法去掉,使用@Autowired注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class User {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String str;

public Cat getCat() {
return cat;
}
public Dog getDog() {
return dog;
}
public String getStr() {
return str;
}
}

2、此时配置文件内容

1
2
3
4
5
<context:annotation-config/>

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="user" class="com.kuang.pojo.User"/>

3、测试,成功输出结果!

【补充】

@Autowired(required=false) 说明:false,对象可以为null;true,对象必须存对象,不能为null。

1
2
3
//如果允许对象为null,设置required = false,默认为true
@Autowired(required = false)
private Cat cat;

9.3 @Qualifier

  • @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配
  • @Qualifier不能单独使用。

测试实验步骤:

1、配置文件修改内容,保证类型存在对象。且名字不为类的默认名字!

1
2
3
4
<bean id="dog1" class="com.kuang.pojo.Dog"/>
<bean id="dog2" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>

2、没有加Qualifier测试,直接报错

3、在属性上添加Qualifier注解

1
2
3
4
5
6
@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;

测试,成功输出!

9.4 @Resource

  • @Resource如有指定的name属性,先按该属性进行byName方式查找装配;
  • 其次再进行默认的byName方式进行装配;
  • 如果以上都不成功,则按byType的方式自动装配。
  • 都不成功,则报异常。

实体类:

1
2
3
4
5
6
7
8
public class User {
//如果允许对象为null,设置required = false,默认为true
@Resource(name = "cat2")
private Cat cat;
@Resource
private Dog dog;
private String str;
}

beans.xml

1
2
3
4
5
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>

<bean id="user" class="com.kuang.pojo.User"/>

测试:结果OK

配置文件2:beans.xml , 删掉cat2

1
2
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>

实体类上只保留注解

1
2
3
4
@Resource
private Cat cat;
@Resource
private Dog dog;

结果:OK

结论:先进行byName查找,失败;再进行byType查找,成功。

9.5 @Nullable <补充>

​ 字段标记了这个注解,说明这个字段可以为null

小结

@Autowired与@Resource异同:

1、@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。

2、@Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用

3、@Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。

十、使用注解开发

10.1 配置

​ 在spring4之后,想要使用注解形式,必须得要引入aop的包

图片

​ 在配置文件当中,还得要引入一个context约束

1
2
3
4
5
6
7
8
9
10
<?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">

</beans>

10.2 bean的实现

1、配置扫描哪些包下的注解

1
2
<!--指定注解扫描包-->
<context:component-scan base-package="com.kuang.pojo"/>

2、在指定包下编写类,增加注解

1
2
3
4
5
@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
public String name = "alen";
}

3、测试

1
2
3
4
5
6
7
@Test
public void test(){
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("beans.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user.name);
}

10.3 属性注入

使用注解注入属性

1、可以不用提供set方法,直接在直接名上添加@value(“值”)

1
2
3
4
5
6
7
@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
@Value("alen")
// 相当于配置文件中 <property name="name" value="alen"/>
public String name;
}

2、如果提供了set方法,在set方法上添加@value(“值”);

1
2
3
4
5
6
7
8
9
10
@Component("user")
public class User {

public String name;

@Value("alen")
public void setName(String name) {
this.name = name;
}
}

10.4 衍生注解

@Component三个衍生注解

为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。

  • @Controller:web层
  • @Service:service层
  • @Repository:dao层

写上这些注解,就相当于将这个类交给Spring管理装配了!

10.5 作用域

@scope

  • singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
  • prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
1
2
3
4
5
6
@Controller("user")
@Scope("prototype")
public class User {
@Value("alen")
public String name;
}

小结:

XML与注解比较

  • XML可以适用任何场景 ,结构清晰,维护方便
  • 注解不是自己提供的类使用不了,开发简单方便

xml与注解整合开发 :推荐最佳实践

  • xml管理Bean
  • 注解完成属性注入
  • 使用过程中, 可以不用扫描,扫描是为了类上的注解
1
<context:annotation-config/>  

作用:

  • 进行注解驱动注册,从而使注解生效
  • 用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册
  • 如果不扫描包,就需要手动配置bean
  • 如果不加注解驱动,则注入的值为null!

10.6 基于Java类进行配置

​ JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本, JavaConfig 已正式成为 Spring4 的核心功能 。

测试:

1、编写一个实体类,Dog

1
2
3
4
@Component  //将这个类标注为Spring的一个组件,放到容器中!
public class Dog {
public String name = "dog";
}

2、新建一个config配置包,编写一个MyConfig配置类

1
2
3
4
5
6
7
8
9
@Configuration  //代表这是一个配置类
public class MyConfig {

@Bean //通过方法注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id!
public Dog dog(){
return new Dog();
}

}

3、测试

1
2
3
4
5
6
7
@Test
public void test2(){
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MyConfig.class);
Dog dog = (Dog) applicationContext.getBean("dog");
System.out.println(dog.name);
}

导入其他配置如何做呢?

1、我们再编写一个配置类!

1
2
3
@Configuration  //代表这是一个配置类
public class MyConfig2 {
}

2、在之前的配置类中我们来选择导入这个配置类

1
2
3
4
5
6
7
8
9
10
@Configuration
@Import(MyConfig2.class) //导入合并其他配置类,类似于配置文件中的 inculde 标签
public class MyConfig {

@Bean
public Dog dog(){
return new Dog();
}

}