0%

Java 企业开发基础 Spring5-IOC

Spring概述

Spring 是轻量级的开源的JavaEE框架。

Spring 可以解决企业应用开发的复杂性

Spring 有两个核心部分:IOC 和 AOP

Spring5模块

特点

  • 方便解耦,简化开发
  • AOP编程支持
  • 方便程序测试
  • 方便和其他框架进行整合
  • 方便进行事务的操作
  • 降低API开发难度

可以使用 maven 包管理工具,也可以下载 Spring 到本地。

下载地址:Spring ,下载完成后,需要将下面几个jar包导入到项目文件中。还需要引入一个日志包。

image-20220926163603438

官网地址:Spring

IOC概述

控制反转IOC

a)把对象创建和对象之间的调用过程,交给Spring进行管理

b)使用IOC目的:为了降低耦合度

底层原理

  • xml解析
  • 工厂模式

若A类中想调用B类中的方法。传统的先创建对象再调用对象中的方法,造成程序的耦合度太高。因此出现了工厂模式,可以有效降低耦合度,但是还是存在耦合:

工厂模式实现过程

  1. 先创建第三个类(工厂类C)
  2. 里面写一个静态static方法,
  3. 在方法里面返回B类的一个对象

则A类就可以通过B类 类名 = C类类名.静态方法名();来调用B类中的方法。

  • 反射

IOC解耦过程⭐

  1. xml配置文件,配置创建的对象 <bean id="dao" class="com.xzt.UserDao"> </bean>
  2. 创建工厂类,实现一个静态方法。方法实现过程。
    • xml解析 String classValue = "com.xzt.UserDao"
    • 通过反射创建对象 Class clazz = Class.forName(classValue);
    • return (UserDao)clazz.newInstance();

接口

IOC 思想基于IOC 容器完成,IOC容器底层就是对象工厂

  • BeanFactory :IOC容器基本实现是Spring内部接口的使用接口,不提供给开发人员进行使用。
  • ApplicationContextBeanFactory接口的子接口,提供更多更强大的功能,提供给开发人员使用。

区别

BeanFactory加载配置文件时候不会创建对象,在获取对象时才会创建对象。ApplicationContext加载配置文件时候就会把在配置文件对象进行创建。推荐使用!!!

ApplicationContext实现类

  • FileSystemXmlApplicationContext 根据系统路径
  • ClassPathXmlApplicationContext 根据src路径

IOC容器-Bean管理

Bean管理

  • Spring创建对象
  • Spring注入属性

基于XML配置文件实现Bean管理

基于XML配置文件创建对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// User.java
package com.xzt;

/**
* @author xzt
* @version 1.0
*/
public class User {
private String name;
public void add() {
System.out.println("add....");
}
}

1
2
<!--1 配置User对象创建-->
<bean id="user" class="com.atguigu.spring5.User"></bean>

在spring配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建。

bean标签的常用属性

  • id属性:唯一标识
  • class属性:类的全路径(包类路径)

注意:创建对象时,默认执行无参构造函数

基于XML配置文件 - 注入属性 - set方式注入⭐

<property name="变量名" value="值"></property>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Book 类
//(1)传统方式: 创建类,定义属性和对应的set方法
public class Book {
//创建属性
private String bname;
private String bauthor;

//创建属性对应的set方法
public void setBname(String bname) {
this.bname = bname;
}

public void setBauthor(String bauthor) {
this.bauthor = bauthor;
}
}
1
2
3
4
5
6
7
8
9
<!--(2)spring方式: set方法注入属性-->
<bean id="book" class="com.atguigu.spring5.Book">
<!--使用property完成属性注入
name:类里面属性名称
value:向属性注入的值
-->
<property name="bname" value="Hello"></property>
<property name="bauthor" value="World"></property>
</bean>

基于XML配置文件 - 注入属性 - 有参构造函数注入⭐

两种方式:

<constructor-arg name="变量名" value="值"></constructor-arg>

<constructor-arg index="变量编号" value="值"></constructor-arg>

1
2
3
4
5
6
7
8
9
10
11
//(1)传统方式:创建类,构建有参函数
public class Orders {
//属性
private String oname;
private String address;
//有参数构造
public Orders(String oname, String address) {
this.oname = oname;
this.address = address;
}
}
1
2
3
4
5
6
7
8
9
10
<!--(2)spring方式:有参数构造注入属性-->
<bean id="orders" class="com.atguigu.spring5.Orders">
<!-- 给oname变量赋值为Hello address变量赋值为China! -->
<constructor-arg name="oname" value="Hello"></constructor-arg>
<constructor-arg name="address" value="China!"></constructor-arg>

<!-- 和上面的效果一样,给第一个参数赋值Hello,给第二个参数赋值China! -->
<constructor-arg index="0" value="Hello"></constructor-arg>
<constructor-arg index="1" value="China!"></constructor-arg>
</bean>

基于XML配置文件 - 注入属性 - p名称空间注入 💤

注意:需要先添加p名称空间在配置文件中

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<!-- 1、添加xmlns:p -->
<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">

<!--2、在bean标签进行属性注入(算是set方式注入的简化操作)-->
<bean id="book" class="com.atguigu.spring5.Book" p:bname="very" p:bauthor="good">
</bean>
</beans>

基于XML配置文件 - 注入空值和特殊符号

可以借助<![CDATA[ ]]>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<bean id="book" class="com.atguigu.spring5.Book">
<!--(1)null值-->
<property name="address">
<null/> <!-- 属性里边添加一个null标签 -->
</property>

<!--(2)特殊符号赋值 -->
<!-- 属性值包含特殊符号
a 把<>进行转义 &lt; &gt;
b 把带特殊符号内容写到CDATA
-->
<property name="address">
<value><![CDATA[<<南京>>]]></value>
</property>
</bean>

基于XML配置文件 - 注入属性 - 外部Bean

创建两个类Service类和Dao类,在Service调用Dao里的方法。

创建userDao接口

1
2
3
4
5
6
7
8
9
10
11
// userDao.java
package com.xzt.dao;

/**
* @author xzt
* @version 1.0
*/
public interface UserDao {
public void update();
}

创建userDaoImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
// UserDaoImpl.java
package com.xzt.dao;

/**
* @author xzt
* @version 1.0
*/
public class UserDaoImpl implements UserDao{
@Override
public void update() {
System.out.println("dao update .....");
}
}

创建userService

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
// UserService.java
package com.xzt.service;

import com.xzt.dao.UserDao;
import com.xzt.dao.UserDaoImpl;

/**
* @author xzt
* @version 1.0
*/
public class UserService {

// 1.创建UserDao属性,生成set方法
private UserDao userDao;

public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}

public void add() {
System.out.println("service add....");

// 传统方式
UserDao userDao = new UserDaoImpl();
userDao.update();

//
}
}

创建bean2.xml进行属性注入(使用set方法进行注入)

  • name属性值: 类里面属性的名字,就是 private UserDao userDao 里面的userDao;
  • ref属性值: 创建userDao对象bean标签的id值
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">
<!-- 1.service和dao对象创建 -->
<bean id="userService" class="com.xzt.service.UserService">
<!--
注入userDao对象
name属性值: 类里面属性的名字 private UserDao userDao;
ref属性值: 创建userDao对象bean标签的id值
-->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.xzt.dao.UserDaoImpl"></bean>
</beans>

基于XML配置文件 - 注入属性 - 内部Bean

作用:一对多关系:部门和员工,一个部门和多个员工。一个员工属于一个部门。在实体类之间表示一对多的关系。

部门类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.xzt.bean;

/**
* @author xzt
* @version 1.0
* 部门类
*/
public class Dept {
private String dname;


public void setDname(String dname) {
this.dname = dname;
}
}

员工类,需要定义一个部门对象,表示该员工所属的部门。

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
package com.xzt.bean;

/**
* @author xzt
* @version 1.0
*/
public class Emp {
private String ename;
private String gender;
// 员工属于某一个部门,定义一个部门对象
private Dept dept;

public void setDept(Dept dept) {
this.dept = dept;
}

public void setEname(String ename) {
this.ename = ename;
}

public void setGender(String gender) {
this.gender = gender;
}
}

分别用 外部 bean内部 bean 实现了配置,两种方式选择一种就可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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写法 -->
<bean id="emp" class="com.xzt.bean.Emp">
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.xzt.bean.Dept"></bean>

<!-- 内部bean写法 -->
<bean id="emp" class="com.xzt.bean.Emp">
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<property name="dept">
<bean id="dept" class="com.xzt.bean.Dept">
<property name="dname" value="安保部"></property>
</bean>
</property>
</bean>
</beans>

基于XML配置文件 - 注入属性 - 级联赋值

同时向有关联的类注入值。上面的内部bean也可以实现这种效果

示例代码:修改上面的xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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="emp" class="com.xzt.bean.Emp">
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!-- 级联赋值 -->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.xzt.bean.Dept">
<property name="dname" value="安保部"></property>
</bean>

<!-- 第二种写法,需要生成对应的get方法 -->
<bean id="emp" class="com.xzt.bean.Emp">
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!-- 级联赋值 -->
<property name="dept" ref="dept"></property>
<property name="dept.dname" value="安保部"></property> <!-- 需要生成dept的get方法-->
</bean>
</beans>

基于XML配置文件 - 注入集合属性-数组

1
2
3
4
5
6
7
<!-- 数组类型注入 -->
<property name="courses">
<array>
<value>java课程</value>
<value>数据库课程</value>
</array>
</property>

基于XML配置文件 - 注入集合属性 - List⭐

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
<!-- list类型注入 -->
<bean>
<property name="list">
<list>
<value>张三</value>
<value>里斯</value>
</list>
</property>

<!-- list类型注入 并且是对象类型的值 -->
<property name="cousers">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>

<!-- 创建多个course对象 -->
<bean id="course1" class="com.xzt.collectiontype.Couser">
<property name="cname" value="Math"></property>
</bean>
<bean id="course2" class="com.xzt.collectiontype.Couser">
<property name="cname" value="Spring"></property>
</bean>
<bean id="course3" class="com.xzt.collectiontype.Couser">
<property name="cname" value="MySql"></property>
</bean>

把集合注入部分提取出来

  • 引入名称空间(类似p名称空间)util
  • 创建<util:list id="id值"> </util:list>

示例代码:和上面的效果一样

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
<?xml version="1.0" encoding="UTF-8"?>
<!-- 1.引入util命名空间 -->
<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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<!-- 2.提取list集合类型属性注入 -->
<util:list id="stringList">
<value>张三</value>
<value>李四</value>
</util:list>
<!-- 3.提取list集合类型属性注入使用 -->
<bean id="string" class="com.xzt.collectiontype.Stu">
<property name="list" ref="stringList"></property>
</bean>
<!-- ----------------------------------------------- -->

<util:list id="courseList">
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</util:list>
<bean id="string" class="com.xzt.collectiontype.Stu">
<property name="list" ref="courseList"></property>
</bean>

<!-- 创建多个course对象 -->
<bean id="course1" class="com.xzt.collectiontype.Couser">
<property name="cname" value="Math"></property>
</bean>
<bean id="course2" class="com.xzt.collectiontype.Couser">
<property name="cname" value="Spring"></property>
</bean>
<bean id="course3" class="com.xzt.collectiontype.Couser">
<property name="cname" value="MySql"></property>
</bean>

</beans>

基于XML配置文件 - 注入集合属性 - Map

1
2
3
4
5
6
7
<!-- map类型注入 key-value -->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>

基于XML配置文件 - 注入集合属性 - Set

1
2
3
4
5
6
7
<!-- set类型注入 -->
<property name="sets">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>

示例代码

编写stu学生类

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
package com.xzt.collectiontype;

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

/**
* @author xzt
* @version 1.0
*/
public class Stu {
// 数组类型属性
private String[] courses;
private List<String> list;
private Map<String, String> maps;

private Set<String> sets;

private List<Couser> cousers;

public void setCousers(List<Couser> cousers) {
this.cousers = cousers;
}

public void setSets(Set<String> sets) {
this.sets = sets;
}

public void setList(List<String> list) {
this.list = list;
}

public void setMaps(Map<String, String> maps) {
this.maps = maps;
}

public void setCourses(String[] courses) {
this.courses = courses;
}
}

编写Course课程类

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.xzt.collectiontype;

/**
* @author xzt
* @version 1.0
*/
public class Couser {
private String cname;

public void setCname(String cname) {
this.cname = cname;
}
}

编写bean.xml配置文件

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
<?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="stu" class="com.xzt.collectiontype.Stu">
<!-- 数组类型注入 -->
<property name="courses">
<array>
<value>java课程</value>
<value>数据库课程</value>
</array>
</property>
<!-- list类型注入 -->
<property name="list">
<list>
<value>张三</value>
<value>里斯</value>
</list>
</property>

<!-- map类型注入 key-value -->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>

<!-- set类型注入 -->
<property name="sets">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>

<!-- list类型注入 并且是对象类型的值 -->
<property name="cousers">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>

</bean>

<!-- 创建多个course对象 -->
<bean id="course1" class="com.xzt.collectiontype.Couser">
<property name="cname" value="Math"></property>
</bean>
<bean id="course2" class="com.xzt.collectiontype.Couser">
<property name="cname" value="Spring"></property>
</bean>
<bean id="course3" class="com.xzt.collectiontype.Couser">
<property name="cname" value="MySql"></property>
</bean>
</beans>

工厂bean (FactoryBean)

普通bean:在配置文件中定义的bean类型就是返回类型。上面所有的都是普通bean。

工厂bean:在配置文件中定义的bean类型可以和返回类型不一样。

  • 创建类,让这个类定义为工厂类,通过实现接口FactoryBean
  • 实现接口里面的方法,在实现的方法中定义返回的 bean 类型

创建工厂类

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
package com.xzt.factorybean;

import com.xzt.collectiontype.Couser;
import org.springframework.beans.factory.FactoryBean;

/**
* @author xzt
* @version 1.0
*/
public class MyBean implements FactoryBean {

// 定义返回bean
@Override
public Object getObject() throws Exception {
Couser couser = new Couser();
return couser;
}

@Override
public Class<?> getObjectType() {
return null;
}

@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}

编写配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<!-- 1.引入util命名空间 -->
<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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<bean id="myBean" class="com.xzt.factorybean.MyBean"> <!-- 定义的类型为 MyBean类型 -->

</bean>
</beans>

编写测试类。返回类型为Course

1
2
3
4
5
6
@Test
public void Test01() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
Couser couser = context.getBean("myBean", Couser.class);// bean的定义类型和返回类型不一样
System.out.println(couser);
}

Bean的作用域

在 spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例

在 Spring 里面,默认情况 下 bean 是 单实例对象 ,下面进行作用域设置

单实例是指一直都是同一个对象,多实例是指创建一次就是一个新的对象。

设置单实例 / 多实例

通过属性scope设置是单实例还是多实例。

scope 属性值

  • singleton 默认值,表示单实例对象。在加载spring配置文件时就会创建单实例对象
  • prototype 表示多实例对象。不是在加载spring配置文件时创建单实例对象,是在使用getBean()方法时创建多实例。
  • request
  • session
1
2
3
<bean id="course1" class="com.xzt.collectiontype.Couser" scope="prototype">
<property name="cname" value="Math"></property>
</bean>

Bean的生命周期

生命周期是一个对象从创建到销毁的过程。

Bean的生命周期

  1. 通过构造器创建Bean实例(无参构造)
  2. 为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
  3. 调用 bean 的初始化的方法(需要进行配置初始化的方法)
  4. bean 可以使用了(对象获取到了)
  5. 当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

实例代码

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
package com.xzt.bean;

import com.sun.tracing.dtrace.ArgsAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* @author xzt
* @version 1.0
*/
public class Orders {
private String oname;

public Orders() {
System.out.println("第一步 执行无参构造创建实例");
}

public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 调用set方法设置值");
}

// 创建执行初始化的方法
public void initMethod(){
System.out.println("第三步 执行初始化方法");
}
// 创建执行销毁的方法
public void initDestory(){
System.out.println("第五步 执行销毁的方法");
}

public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
Orders order = context.getBean("order", Orders.class);
System.out.println("第四步 获取创建bean实例对象");
System.out.println(order);

((ClassPathXmlApplicationContext) context).close(); // 手动销毁
}
}

编写配置文件

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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- init-method: 初始化方法是调用 destroy-method:销毁方法时调用 -->
<bean id="order" class="com.xzt.bean.Orders" init-method="initMethod" destroy-method="initDestory">
<property name="oname" value="aaa"></property>
</bean>
</beans>

image-20220926212401428

Bean 的后置处理器

bean 生命周期有七步 (正常生命周期为五步,而配置后置处理器后为七步)

  1. 通过构造器创建 bean 实例(无参数构造)
  2. 为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
  3. 把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization 💡
  4. 调用 bean 的初始化的方法(需要进行配置初始化的方法)
  5. 把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization 💡
  6. bean 可以使用了(对象获取到了)
  7. 当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

后置处理器的实现方法:创建一个类MyBeanPost,实现一个接口 BeanPostProcessor。并且在xml中配置后置处理器

1
2
<bean id="myBeanPost" class="com.xzt.bean.MyBeanPost"></bean>
<!-- 配置后置处理器,会对当前xml文件中的所有配置都添加上后置处理器 -->

Bean管理

XML自动装配

1
2
3
4
5
6
7
8
9
package com.xzt.autowire;

/**
* @author xzt
* @version 1.0
*/
public class Dept {
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.xzt.autowire;

/**
* @author xzt
* @version 1.0
*/
public class Emp {
private Dept dept;

public void setDept(Dept dept) {
this.dept = dept;
}

@Override
public String toString() {
return "Emp{" +
"dept=" + dept +
'}';
}
}

1
2
3
4
5
<!-- 手动装配 -->
<bean id="emp" class="com.xzt.autowire.Emp">
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.xzt.autowire.Dept"></bean>

bean标签属性autowire 用来配置自动装配。autowire属性有两个值:

  • byName 根据属性名称注入。需要注入bean的id值和类对象名称一样。
1
2
3
4
5
6
<!-- 实现自动装配-byName -->
<bean id="emp" class="com.xzt.autowire.Emp" autowire="byName">
</bean>
<!-- 这里的id值必须和Emp类中的Dept对象名称相同 -->
<bean id="dept" class="com.xzt.autowire.Dept"></bean>

  • byType 根据类型属性注入。存在缺陷,相同的类不能创建多个。
1
2
3
4
<!-- 实现自动装配-byType -->
<bean id="emp" class="com.xzt.autowire.Emp" autowire="byType">
</bean>
<bean id="dept" class="com.xzt.autowire.Dept"></bean>

引入外部属性文件

直接配置数据库信息

  1. 配置Druid(德鲁伊)连接池
  2. 引入Druid(德鲁伊)连接池依赖 jar 包

配置Druid(德鲁伊)连接池

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 id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
</beans>

引入外部属性文件配置数据库连接池⭐⭐

  1. 创建外部属性文件,properties 格式文件,写数据库信息(jdbc.properties
1
2
3
4
5
# jdbc.properties
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/userDb
prop.userName=root
prop.password=root
  1. 把外部 properties 属性文件引入到 spring 配置文件中 —— 引入 context 名称空间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<!-- 引入context名称空间 -->
<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:util="http://www.springframework.org/schema/util"
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/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 引入外部属性文件配置连接池 -->
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>

<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
</beans>

基于注解方式引入对象

注解:是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值)

作用位置:注解可以作用在类上、方法上、属性上面。

目的:简化xml配置

spring针对Bean管理中创建对象提供注解

  • @Component 普通注解
  • @Service 用在业务逻辑层
  • @Controller 用在Web层
  • @Repository 用在Dao层

上面的四个注解,功能相同,都可以用来创建Bean实例。

基于注解方式实现对象创建步骤⭐⭐

  1. 引入AOP依赖spring-aop-5.3.23.jar

  2. 开启组件扫描。在配置文件中引入名称空间context,然后编写配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <?xml version="1.0" encoding="UTF-8"?>
    <!-- 引入context名称空间 -->
    <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:util="http://www.springframework.org/schema/util"
    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/util http://www.springframework.org/schema/util/spring-util.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 开启组件扫描,两种写法
    1.如果扫描多个包,多个包使用逗号隔开
    2.扫描包上层目录
    -->
    <context:component-scan base-package="com.xzt.dao, com.xzt.service, com.xzt.controller"></context:component-scan>
    <context:component-scan base-package="com.xzt"></context:component-scan>
    </beans>
  3. 创建类,在类上面添加创建对象注释。

    加四个注解中的其中任何一个都可以。并且其中 value属性值可以不写。默认就是类名称首字母小写。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    package com.xzt.service;

    import org.springframework.stereotype.Service;

    /**
    * @author xzt
    * @version 1.0
    * 用注解方式创建对象
    */
    // 加四个注解中的其中任何一个都可以,
    // value属性值可以不写。默认就是类名称首字母小写。
    @Service(value = "userService") // <bean id="userService" class="..."/>
    public class UserService {

    public void add() {
    System.out.println("servcie add....");
    }
    }

测试

1
2
3
4
5
6
7
@Test
public void testService() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); // 引入配置文件,
UserService userService = context.getBean("userService", UserService.class); // 创建对象
System.out.println(userService);
userService.add();
}

开启组件扫描配置细节

  • use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter。context:include-filter 标签设置扫描哪些内容
  • context:exclude-filter 标签设置哪些注解不扫描。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--示例 1
use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter
context:include-filter ,设置扫描哪些内容
type="annotation" 根据注解进行扫描
-->
<context:component-scan base-package="com.atguigu" use-defaultfilters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <!--代表只扫描Controller注解的类-->
</context:component-scan>

<!--示例 2
下面配置扫描包所有内容
context:exclude-filter: 设置哪些内容不进行扫描
-->
<context:component-scan base-package="com.atguigu">
<!--表示Controller注解的类之外一切都进行扫描-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

基于注解方式实现属性注入

常用于属性注入的注解

  • @AutoWired 根据属性类型进入自动注入
  • @Qualifier(value="名称") 根据属性名称进行注入。需要和@AutoWired一起使用
  • @Resource 可以根据类型注入@Resource,也可以根据名称注入 @Resource(name="名称"),不建议用
  • @Value(value = "值") 注入普通类型属性。

基于注解属性注入步骤 ⭐⭐

  1. 把 servcie 和 dao 对象创建,在 service 和 dao 类添加创建对象注释。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package com.xzt.dao;

    import org.springframework.stereotype.Repository;

    /**
    * @author xzt
    * @version 1.0
    */
    @Repository(value = "userDaoImpl1")
    public class UserDaoImpl implements UserDao{
    @Override
    public void add() {
    System.out.println("dao add......");
    }
    }

  2. 在 service 里注入 dao 对象,在 service 类添加 dao 类型属性。在属性上面使用注解。不需要加set方法

    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
    package com.xzt.service;

    import com.xzt.dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;

    /**
    * @author xzt
    * @version 1.0
    * 用注解方式创建对象
    */
    // 加四个注解中的其中任何一个都可以,
    // value属性值可以不写。默认就是类名称首字母小写。
    @Service(value = "userService") // <bean id="userService" class="..."/>
    public class UserService {

    // 定义dao类型属性
    @Autowired
    @Qualifier(value = "userDaoImpl1") // 和@Repository(value = "userDaoImpl1")这里的对应
    private UserDao userDao;

    @Value(value = "abc")
    private String name;

    public void add() {
    System.out.println("servcie add....");
    userDao.add(); // 调用dao里的add方法
    }
    }

纯注解开发

步骤

  1. 创建配置类SpringConfig.java,替代xml配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package com.xzt.config;

    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;

    /**
    * @author xzt
    * @version 1.0
    */
    @Configuration // 把当前类作为配置类,用这个类替代xml配置文件
    @ComponentScan(basePackages = {"com.xzt"}) // 包扫描
    public class SpringConfig {
    }
  2. 加载配置类的方式需要改变

    1
    2
    //ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");  // 根据xml配置文件加载
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); // 根据配置类加载
正在加载今日诗词....