学习内容
- Spring 概念
- IOC 容器
- AOP
- JdbcTemplate
- 事务管理
- Spring5 新特性
Spring 框架概述
-
Spring 是轻量级的开源 JavaEE 框架
-
Spring 可以解决企业应用开发的复杂性
-
Spring 有两个核心部分:IOC 和 AOP
- IOC:控制反转,将创建对象过程交给 Spring 进行管理
- AOP:面向切面,在不修改源代码的情况下,进行功能增强
-
Spring 的特点
- 方便解耦,简化开发
- AOP 编程支持
- 方便程序的测试
- 方便和其它框架进行整合
- 方便进行事务操作
- 降低 API 开发
入门案例
-
下载 Spring5
-
创建 Spring项目
-
导入 Spring5 相关 jar 包:Project Structure -> Modules -> "+" JARs
- Beans、Core、Context、Expression
-
创建普通类,在这个类中创建一个普通的方法
package com.atjava.spring5;
/**
* @author lv
* @create 2021-11-12 22:12
*/
public class User {
public void add () {
System.out.println("add...");
}
}
- 创建 Spring 配置文件,在配置文件中配置创建的对象
- Spring 配置文件使用 xml 格式
- bean 标签,属性 id表示类名、class表示类的文件路径
<?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">
<!--配置 User类对象的 创建-->
<bean id="user" class="com.atjava.spring5.User"></bean>
</beans>
- 进行测试代码编写
- ApplicationContext 获取指定的 xml配置文件
- ClassPathXmlApplicationContext 可以直接获取在 src 下的 xml配置文件
- getBean() 创建指定的 类对象
package com.atjava.test;
import com.atjava.spring5.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author lv
* @create 2021-11-12 22:22
*/
public class TestSpring5 {
@Test
public void testAdd () {
// 1.加载 Spring配置文件
ApplicationContext context
= new ClassPathXmlApplicationContext("bean1.xml");
// 2.获取配置文件创建的对象
User user = context.getBean("user", User.class);
System.out.println(user);
user.add();
}
}
IOC 容器
IOC 原理
IOC 的作用
- 控制反转,将对象创建和对象之间的调用过程,交给 Spring进行管理
- 使用 IOC目的:降低各类之间的耦合度
IOC 底层原理
- xml 解析
- 工厂模式
- 反射
图解 IOC底层原理
- 第一步,xml配置文件,配置创建的对象
<bean id="userDao" class="com.atjava.UserDao"></bean>
- 第二步,创建工厂类,解析 xml,通过 反射创建对象
class XxxFactory {
public static UserDao getDao () {
// 1.解析 xml
String classValue = class属性值;
// 2.通过反射创建对象
Class clazz = Class.forName(classValue);
return (UserDao)clazz.newInstance();
}
}
IOC 接口(BeanFactory)
- IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂
Spring 提供 IOC 容器实现两种方式:(两个接口)
- BeanFactory:IOC容器基本实现,是 Spring的内部使用接口,不推荐开发人员使用;
注意,使用此接口加载配置文件时不会创建对象,在获取(使用)对象时,才会创建对象 - ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能给开发者使用;
此接口在加载配置文件时就会创建配置文件中所有的对象
ApplicationContext 接口的实现类
- FileSystemXmlApplicationContext:需写出配置文件具体的盘符路径
- ClassPathXmlApplicationContext:专门获取 src下的配置文件
IOC 操作 Bean 管理
Bean 管理,指的是两个操作
- Spring
创建对象 - Spring
注入属性
IOC 操作 Bean 管理(基于 xml)
基于 xml方式创建对象:
- 在 Spring 配置文件中,使用 bean标签,标签中添加对象属性,可以完成对象的创建
- bean标签中很多属性,介绍常用属性
- id 属性:唯一标识
- class 属性:类全路径(包类路径)
- 创建对象时,默认是执行无参数构造方法完成对象创建
基于 xml 方式注入属性: DI是 IOC中的一种具体实现,它表示 依赖注入。
- DI:依赖注入,就是注入属性,需在创建对象的基础上完成
- property标签,设置属性值
第一种注入方式:使用 set方法进行注入:
- 使用 set方法,注入属性
- 在类中添加对应属性的 setXxx()方法,在 xml中添加对应属性的 property标签
<bean id="book" class="com.atjava.spring5.Book">
<!--
set 方法注入属性:
name:类中属性名称
value:向属性中注入值
-->
<property name="bName" value="易筋经"></property>
<property name="bAuthor" value="少林"></property>
</bean>
package com.atjava.spring5;
/**
* @author lv
* @create 2021-11-14 12:13
*/
public class Book {
private String bName;
private String bAuthor;
public void setbName(String bName) {
this.bName = bName;
}
public void setbAuthor(String bAuthor) {
this.bAuthor = bAuthor;
}
@Override
public String toString() {
return "Book{" +
"bName='" + bName + ''' +
", bAuthor='" + bAuthor + ''' +
'}';
}
}
@Test
public void testBook () {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Book book = context.getBean("book", Book.class);
System.out.println(book); // Book{bName='易筋经', bAuthor='少林'}
}
第二种注入方式:使用有参数构造进行注入:
- constructor-arg标签,设置对应的构造参数值
<bean id="orders" class="com.atjava.spring5.Orders">
<constructor-arg name="oName" value="123"></constructor-arg>
<constructor-arg index="2" value="789"></constructor-arg>
<constructor-arg name="address" value="456"></constructor-arg>
</bean>
package com.atjava.spring5;
import java.math.BigDecimal;
/**
* @author lv
* @create 2021-11-14 15:21
*/
public class Orders {
private String oName;
private String address;
private BigDecimal price;
public Orders() {
}
public Orders(String oName, String address) {
this.oName = oName;
this.address = address;
}
public Orders(String oName, String address, BigDecimal price) {
this.oName = oName;
this.address = address;
this.price = price;
}
@Override
public String toString() {
return "Orders{" +
"oName='" + oName + ''' +
", address='" + address + ''' +
", price=" + price +
'}';
}
}
@Test
public void testOrders () {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println(orders.toString());
// Orders{oName='123', address='456', price=789}
}
第三种注入方式:使用 p名称空间 进行注入,简化property注入方式(了解):
- 在配置文件中,添加 p名称空间
xmlns:p="http://www.springframework.org/schema/p" - 进行属性注入,在 bean标签里面进行操作
<?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="book" class="com.atjava.spring5.Book">-->
<!--<!–-->
<!--set 方法注入属性:-->
<!--name:类中属性名称-->
<!--value:向属性中注入值-->
<!--–>-->
<!--<property name="bName" value="易筋经"></property>-->
<!--<property name="bAuthor" value="少林"></property>-->
<!--</bean>-->
<bean id="book" class="com.atjava.spring5.Book" p:bName="九阴震惊" p:bAuthor="作者"></bean>
</beans>
字面量:
- null值:
- 属性值包含特殊符号
- 特殊符号转义
- <![CDATA[xxx]]>
<bean id="book" class="com.atjava.spring5.Book">
<!--
set 方法注入属性:
name:类中属性名称
value:向属性中注入值
-->
<property name="bName" value="易筋经"></property>
<property name="bAuthor" value="少林"></property>
<!--
设置属性值为 null
-->
<property name="pages">
<null />
</property>
<!--
属性值包含特殊符号
1. 将 <>进行转义 < >
2. 将含有特殊符号的值放到 CDATA中
-->
<property name="publish">
<value><![CDATA[<@北平>]]></value>
</property>
</bean>
注入属性,外部 bean
- 创建两个类 service类 和 dao类
package com.atjava.spring5.dao;
/**
* @author lv
* @create 2021-11-14 21:12
*/
public interface UserDao {
public void update ();
}
// ...
package com.atjava.spring5.dao;
/**
* @author lv
* @create 2021-11-14 21:13
*/
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("dao update......");
}
}
- 在 service中调用 dao里面的方法
- 将 外部类设置为 此类的属性
package com.atjava.spring5.service;
import com.atjava.spring5.dao.UserDao;
/**
* @author lv
* @create 2021-11-14 21:11
*/
public class UserService {
// 创建 UserDao类型属性,生成 set方法
private UserDao userDao;
public void setUserDao (UserDao userDao) {
this.userDao = userDao;
}
public void add () {
System.out.println("add.......");
/**
* 在 service中调用 dao中的方法:
*/
// 1.使用普通方法调用
// UserDao userDao2 = new UserDaoImpl();
// userDao2.update();
// 2.使用 xml方式调用
userDao.update();
}
}
- 在 Spring配置文件中进行配置
- ref属性值:是 xml文件中 bean标签的 id属性值
<?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="userService" class="com.atjava.spring5.service.UserService">
<!--
注入外部 bean:
name属性值:类中属性名称
ref属性值:xml中 bean标签 id属性值
-->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.atjava.spring5.dao.UserDaoImpl"></bean>
</beans>
注入属性,内部 bean 和 级联赋值 数据库中的表关系有:一对多、一对一、多对多,内部 bean 和 级联赋值就与此有关。
- 一对多关系:部门和员工
- 在实体类之间表示 一对多关系,员工表示所属部门,使用对象类型属性进行表示
- 在 Spring 的 xml配置文件中进行相关配置
- 部门和员工类
package com.atjava.spring5.bean;
/**
* @author lv
* @create 2021-11-21 11:28
*/
public class Dept {
private String dName;
public void setdName(String dName) {
this.dName = dName;
}
@Override
public String toString() {
return "Dept{" +
"dName='" + dName + ''' +
'}';
}
}
package com.atjava.spring5.bean;
/**
* @author lv
* @create 2021-11-21 11:30
*/
public class Emp {
private String eName;
private String gender;
// 员工部门,使用对象形式表示
private Dept dept;
public void seteName(String eName) {
this.eName = eName;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"eName='" + eName + ''' +
", gender='" + gender + ''' +
", dept=" + dept +
'}';
}
}
- Spring中的 xml配置
- 内部 bean
- 级联赋值
<?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 和 级联操作
1. 内部 bean,在一个 bean中,内部可以嵌套另一个 bean
-->
<bean id="emp" class="com.atjava.spring5.bean.Emp">
<!--普通属性设置-->
<property name="eName" value="lv"></property>
<property name="gender" value="男"></property>
<!--
对象类型属性设置:
内部 bean 的设置
-->
<property name="dept">
<bean id="dept" class="com.atjava.spring5.bean.Dept">
<property name="dName" value="安保部"></property>
</bean>
</property>
</bean>
<!--
级联赋值:
-->
<bean id="emp2" class="com.atjava.spring5.bean.Emp">
<!--普通属性设置-->
<property name="eName" value="lv"></property>
<property name="gender" value="男"></property>
<!--
对象类型属性设置:
内部 bean 的设置
-->
<property name="dept" ref="dept2"></property>
</bean>
<bean id="dept2" class="com.atjava.spring5.bean.Dept">
<property name="dName" value="财务部"></property>
</bean>
</beans>
IOC 操作 Bean 管理(xml 注入集合属性)
- 注入 数组类型属性 array value
- 注入 List集合类型属性 list value
- 注入 Map集合类型属性 map、entry
- 注入 Set集合类型属性 set value
package com.atjava.collectiontype;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author lv
* @create 2021-11-21 15:33
*/
public class Stu {
// 数组类型属性
private String[] courses;
// list集合类型属性
private List<String> list;
// map集合类型属性
private Map<String, String> maps;
// set集合类型属性
private Set<String> sets;
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
@Override
public String toString() {
return "Stu{" +
"courses=" + Arrays.toString(courses) +
", list=" + list +
", maps=" + maps +
", sets=" + sets +
'}';
}
}
<?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.atjava.collectiontype.Stu">
<!--数组类型属性注入-->
<property name="courses">
<!--<list></list>-->
<array>
<value>java</value>
<value>javaScript</value>
<value>sql</value>
</array>
</property>
<!--list类型属性注入-->
<property name="list">
<list>
<value>张三</value>
<value>小三</value>
</list>
</property>
<!--map类型属性注入-->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="JavaScript" value="js"></entry>
</map>
</property>
<!--set类型属性注入-->
<property name="sets">
<set>
<value>MySql</value>
<value>Redis</value>
</set>
</property>
</bean>
</beans>
在集合中设置对象类型的值:
- 使用 ref标签引入对象
<?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.atjava.collectiontype.Stu">
<!--集合类型的属性中存放对象-->
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<!--创建多个 course对象-->
<bean id="course1" class="com.atjava.collectiontype.Course">
<property name="cName" value="java"></property>
</bean>
<bean id="course2" class="com.atjava.collectiontype.Course">
<property name="cName" value="JavaScript"></property>
</bean>
</beans>
package com.atjava.collectiontype;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author lv
* @create 2021-11-21 15:33
*/
public class Stu {
private List<Course> courseList;
public void setCourseList(List<Course> courseList) {
this.courseList = courseList;
}
@Override
public String toString() {
return "Stu{" +
"courses=" + Arrays.toString(courses) +
", list=" + list +
", maps=" + maps +
", sets=" + sets +
", courseList=" + courseList +
'}';
}
}
将集合注入部分提取出来,作为公共部分
- beans标签添加属性
xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" - 使用 utils:xxx标签,提取对应的集合类型
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
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
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--提取 list集合类型属性,作为公共部分-->
<util:list id="bookList">
<value>java</value>
<value>JavaScript</value>
<value>React</value>
</util:list>
<!--将提取出的部分 bookList,注入使用-->
<bean id="book" class="com.atjava.collectiontype.Book">
<property name="list" ref="bookList">
<!--将此部分提取出来,作为公共部分使用-->
<!--<list>-->
<!--<value>java</value>-->
<!--<value>JavaScript</value>-->
<!--<value>React</value>-->
<!--</list>-->
</property>
</bean>
</beans>
package com.atjava.collectiontype;
import java.util.List;
/**
* @author lv
* @create 2021-11-21 17:05
*/
public class Book {
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
@Override
public String toString() {
return "Book{" +
"list=" + list +
'}';
}
}
IOC 操作 Bean管理(FactoryBean)
- Spring 有两种类型 bean,一种是普通 bean,另一种是工厂 bean(FactoryBean)
- 普通 bean:在配置文件中定义 bean类型就是返回类型
- 工厂 bean:在配置文件中定义 bean类型可以返回和返回的类型不同
- 第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
- 第二部 实现接口里面的方法,在实现的方法中定义返回的 bean类型
package com.atjava.collectiontype.factorybean;
import com.atjava.collectiontype.Course;
import org.springframework.beans.factory.FactoryBean;
/**
* @author lv
* @create 2021-11-22 22:58
*/
public class MyBean implements FactoryBean<Course> {
/**
* 定义返回 bean类型
*
*/
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setcName("芜湖");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
<?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="myBean" class="com.atjava.collectiontype.factorybean.MyBean"></bean>
</beans>
@Test
public void testBean () {
ApplicationContext context = new ClassPathXmlApplicationContext("factoryBean.xml");
Course myBean = context.getBean("myBean", Course.class);
System.out.println(myBean); // Course{cName='芜湖'}
}
IOC 操作 Bean 管理(bean作用域)
- 在 Spring中,设置创建 bean实例是 单实例还是 多实例
- 在 Spring中,默认情况下,bean是单实例对象
- 在 Spring中,设置对象的单实例或多实例方法
- 在 Spring配置文件的 bean标签中通过属性 scope属性,设置单例多例
- scope属性值:singleton (默认)单实例、prototype多实例、request、session
- 单实例和多实例的特点:
- singleton单实例,在加载 Spring配置文件时就会去创建单实例对象
- prototype多实例,只有在调用方法 getBean(...)时,才会去创建新的多实例对象
- request,创建的对象会放到 request域对象中
- session,创建的对象会放到 session域对象中
<bean id="book" class="com.atjava.collectiontype.Book" scope="prototype">
<property name="list" ref="bookList">
</property>
</bean>
// com.atjava.collectiontype.Book@7a36aefa
// com.atjava.collectiontype.Book@17211155
IOC 操作 Bean 管理(bean的生命周期)
bean 的生命周期
- 通过 构造器创建 bean实例(无参构造器)
- 为 bean的属性设置值和对其它 bean引用(调用 set方法)
- 将 bean实例传递给 bean后置处理器的方法
- 调用 bean的初始化方法(需要进行配置初始化的方法)
- 将 bean实例传递给 bean后置处理器的方法
- bean可以使用了(对象获取到了)
- 当容器关闭时,调用 bean的销毁方法(需要进行配置销毁的方法)
- bean的后置处理器,bean生命周期共有七步
- 通过 构造器创建 bean实例(无参构造器)
- 为 bean的属性设置值和对其它 bean引用(调用 set方法)
- 将 bean实例传递给 bean后置处理器的方法 postProcessBeforeInitialization
- 调用 bean的初始化方法(需要进行配置初始化的方法)
- 将 bean实例传递给 bean后置处理器的方法 postProcessAfterInitialization
- bean可以使用了(对象获取到了)
- 当容器关闭时,调用 bean的销毁方法(需要进行配置销毁的方法)
bean 生命周期的演示
- 手动调用销毁方法 context.close();
package com.atjava.collectiontype.bean;
import org.springframework.core.annotation.Order;
/**
* @author lv
* @create 2021-11-25 22:47
*/
public class Orders {
private String oName;
public Orders () {
System.out.println("第一步:执行无参构造,创建 bean实例");
}
public void setoName(String oName) {
System.out.println("第二步:调用 setXxx方法,设置属性");
this.oName = oName;
}
// 创建 bean执行初始化的方法,无需手动调用
public void initMethod () {
System.out.println("第三步:创建 bean执行初始化的方法");
}
// 创建 bean执行销毁的方法,需手动调用
public void destroyMethod () {
System.out.println("第五步:创建 bean销毁的方法");
}
}
<?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:指定初始化的方法
-->
<bean
id="orders"
class="com.atjava.collectiontype.bean.Orders"
init-method="initMethod"
destroy-method="destroyMethod"
>
<property name="oName" value="jiji"></property>
</bean>
</beans>
@Test
public void testBean2 () {
// ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("第四步:获取创建 bean实例的对象");
System.out.println(orders);
// ((ClassPathXmlApplicationContext) context).close();
// 手动调用销毁方法
context.close();
/**
* 第一步:执行无参构造,创建 bean实例
* 第二步:调用 setXxx方法,设置属性
* 在 第三步:初始化之前执行的方法
* 第三步:创建 bean执行初始化的方法
* 在 第三步:初始化之后执行的方法
* 第四步:获取创建 bean实例的对象
* com.atjava.collectiontype.bean.Orders@33723e30
* 第五步:创建 bean销毁的方法
*/
}
bean 演示添加后置处理器的效果
- 创建类,实现接口 BeanPostProcessor,创建后置处理器
package com.atjava.collectiontype.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @author lv
* @create 2021-11-25 23:23
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在 第三步:初始化之前执行的方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在 第三步:初始化之后执行的方法");
return bean;
}
}
- 在配置文件中添加 后置处理器实现类
<?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:指定初始化的方法
-->
<bean
id="orders"
class="com.atjava.collectiontype.bean.Orders"
init-method="initMethod"
destroy-method="destroyMethod"
>
<property name="oName" value="jiji"></property>
</bean>
<!--
配置后置处理器 MyBeanPostProcessor
当在 配置文件中,添加了实现 BeanPostProcessor的类时,
配置文件会为配置文件中的所有 bean实例,默认添加此后置处理器
-->
<bean id="myBeanPostProcessor" class="com.atjava.collectiontype.bean.MyBeanPostProcessor"></bean>
</beans>
IOC 操作 Bean 管理(xml 自动装配)
自动装配: 根据指定的装配规则(属性名称或属性类型),Spring 自动将匹配的属性值进行注入
演示自动装配过程
- bean标签属性 autowire,配置自动装配
- autowire属性常用的两个值:
- byName 根据属性名称注入,注入值 bean的 id值和类属性名称一样
- byType 根据属性类型注入
<?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标签属性 autowire,配置自动装配
autowire 属性常用两个值:
byName根据属性名称注入,注入值 bean的 id值和类属性名称一样
byType根据属性类型注入,
-->
<!--<bean id="emp" class="com.atjava.autowrite.Emp" autowire="byName">-->
<bean id="emp" class="com.atjava.autowrite.Emp" autowire="byType">
<!--手动装配-->
<!--<property name="dept" ref="dept"></property>-->
</bean>
<bean id="dept" class="com.atjava.autowrite.Dept"></bean>
</beans>
IOC 操作 Bean 管理(外部属性文件,数据库必备)
直接配置数据库信息
- 配置德鲁伊连接池
- 引入德鲁伊连接池依赖 jar包
<?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">
<!--
配置 druid连接池
使用 properties配置文件
-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--
driverClassName:驱动名称
// com.mysql.jabc.Driver
url:数据库地址
// jdbc:mysql://localhost:3306/userDb
username:数据库用户名 root
password:密码 root
-->
<property name="driverClassName" value="com.mysql.jabc.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>
引入外部属性文件配置数据库连接池
- 创建外部属性文件 jdbc.properties,写入数据库信息
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/userDb
prop.username=root
prop.password=root
-
将外部 properties属性配置文件,引入到 Spring配置文件中,使用 context名称空间
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/beans/spring-context.xsd"- 在 Spring配置文件中使用标签 context 引入外部属性文件
-
实例:
<?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/beans/spring-context.xsd"
>
<!--
配置 druid连接池
使用 properties配置文件
-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--
driverClassName:驱动名称
// com.mysql.jabc.Driver
url:数据库地址
// jdbc:mysql://localhost:3306/userDb
username:数据库用户名 root
password:密码 root
-->
<!--
引入外部属性文件:
classpath:在 src文件下使用
-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<property name="driverClassName" value="${prop.driverclass}"></property>
<property name="url" value="${prop.username}"></property>
<property name="username" value="${prop.username}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
</beans>
IOC 操作 Bean 管理(基于注解方式)
注解:
- 注解是代码特殊标记,格式:
@注解名称(属性名称=属性值,属性名称=属性值...) - 使用注解,注解可以作用在 类、属性、方法上
- 使用注解的目的,简化 xml配置,使用更优雅、更简便的方式实现配置
Spring 针对 Bean管理中创建对象提供的注解 以下四个注解功能是一样的,都可以用来创建 Bean实例,但建议不同的注解用于不同的 Bean实例
- @Component:普通注解,一般都能使用
- @Service:一般用于业务逻辑层 或 service层
- @Controller:一般用于 web层
- @Repository:一般用于 DAO层 或 持久层
基于注解方式实现对象创建
- 第一步,引入依赖 spring-aop-5.2.6.RELEASE.jar
- 第二步,开启组件扫描
- 如果多个包,多个包分别使用逗号隔开
- 扫描包上层目录
- 创建类,在类上面添加创建对象注解
- 实例测试:
<?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">
<!--
Bean管理,基于注解方式
开启组件扫描:
base-package:标明扫描的文件
1.如果多个包,多个包分别使用逗号隔开
2.扫描包上层目录
-->
<!--<context:component-scan base-package="com.atjava.spring5.service,com.atjava.spring5.dao"></context:component-scan>-->
<context:component-scan base-package="com.atjava.spring5"></context:component-scan>
</beans>
package com.atjava.spring5.service;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* @author lv
* @create 2021-12-09 23:28
*/
/**
* 在注解里面 value属性值可以省略不写,
* 默认值为类名称,首字母小写
*/
//@Component(value = "userService") // 此功能与 xml中 <bean id="userService" class="..." /> 类似
@Service(value = "userService")
public class UserService {
public void add() {
System.out.println("add userService ...");
}
}
package com.atjava.spring5.test;
import com.atjava.spring5.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author lv
* @create 2021-12-09 23:34
*/
public class TestSpring5 {
@Test
public void testSpring () {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
/**
* com.atjava.spring5.service.UserService@f2f2cc1
* add userService ...
*/
}
}
开启组件扫描细节配置
- 属性 use-default-filters="false":表示不使用 Spring默认的 filter,使用自己设置的 filter
- 标签 context:include-filter:设置被扫描的内容
- 标签 context:exclude-filter:设置不被扫描的内容
- 属性 type="annotation":表示注解
- 属性 expression="...":表示路径
<?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">
<!--
Bean管理,基于注解方式
开启组件扫描:
base-package:标明扫描的文件
1.如果多个包,多个包分别使用逗号隔开
2.扫描包上层目录
-->
<!--<context:component-scan base-package="com.atjava.spring5.service,com.atjava.spring5.dao"></context:component-scan>-->
<context:component-scan base-package="com.atjava.spring5"></context:component-scan>
<!--
示例1:
use-default-filters="false":表示不使用默认 filter,使用自己配置的 filter
context:include-filter:设置被扫描的内容
-->
<context:component-scan base-package="com.atjava.spring5" use-default-filters="false">
<context:include-filter
type="annotation"
expression="org.springframework.stereotype.Controller"
></context:include-filter>
</context:component-scan>
<!--
示例2:
context:exclude-filter:设置不被扫描的内容
-->
<context:component-scan base-package="com.atjava">
<context:exclude-filter
type="annotation"
expression="org.springframework.stereotype.Controller"
></context:exclude-filter>
</context:component-scan>
</beans>
基于注解方式实现属性注入
-
@Autowired:根据属性类型进行自动装配
-
@Qualifier:根据属性名称进行注入
-
@Resource:根据属性类型注入 或 根据属性名称注入
-
@Value:注入普通类型属性
@Autowired:根据属性类型进行自动装配
- 把 service和 dao对象创建,在 service和 dao类添加创建对象注解
- 在 service注入 dao对象,在 service类添加 dao对象类型属性,在属性上使用注解
package com.atjava.spring5.dao;
import org.springframework.stereotype.Repository;
/**
* @author lv
* @create 2021-12-10 22:34
*/
@Repository(value = "userDaoImpl")
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("userDao add...");
}
}
package com.atjava.spring5.service;
import com.atjava.spring5.dao.UserDao;
import com.atjava.spring5.dao.UserDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* @author lv
* @create 2021-12-09 23:28
*/
/**
* 在注解里面 value属性值可以省略不写,
* 默认值为类名称,首字母小写
*/
//@Component(value = "userService") // 此功能与 xml中 <bean id="userService" class="..." /> 类似
@Service(value = "userService")
public class UserService {
/**
* 定义 dao类型属性
* 不需要添加 set方法
* 添加注入属性注解
*/
@Autowired // 根据类型实现注入,类似于 bean标签的 byType
private UserDao userDao;
// public void setUserDao(UserDao userDao) {
// this.userDao = userDao;
// }
public void add() {
System.out.println("add userService ...");
userDao.add();
}
}
package com.atjava.spring5.test;
import com.atjava.spring5.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author lv
* @create 2021-12-09 23:34
*/
public class TestSpring5 {
@Test
public void testSpring () {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
/**
* com.atjava.spring5.service.UserService@501edcf1
* add userService ...
* userDao add...
*/
}
}
@Qualifier:根据属性名称进行注入
- 这个 @Qualifier 注解的使用的前提,要和上面的 @Autowired一起使用
- 因为一个接口的实现类可能不止一个,如果只靠类型去获取对应的实现类时,无法判断具体是哪个实现类,所以需要对应实现类的 名称进行获取
package com.atjava.spring5.dao;
import org.springframework.stereotype.Repository;
/**
* @author lv
* @create 2021-12-10 23:02
*/
@Repository(value = "userDaoImpl2")
public class UserDaoImpl2 implements UserDao {
@Override
public void add() {
System.out.println("userDaoImpl2 add...");
}
}
package com.atjava.spring5.service;
import com.atjava.spring5.dao.UserDao;
import com.atjava.spring5.dao.UserDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* @author lv
* @create 2021-12-09 23:28
*/
/**
* 在注解里面 value属性值可以省略不写,
* 默认值为类名称,首字母小写
*/
//@Component(value = "userService") // 此功能与 xml中 <bean id="userService" class="..." /> 类似
@Service(value = "userService")
public class UserService {
/**
* 定义 dao类型属性
* 不需要添加 set方法
* 添加注入属性注解
*/
@Autowired // 根据类型实现注入,类似于 bean标签的 byType
@Qualifier(value = "userDaoImpl2")
private UserDao userDao;
// public void setUserDao(UserDao userDao) {
// this.userDao = userDao;
// }
public void add() {
System.out.println("add userService ...");
userDao.add();
}
}
package com.atjava.spring5.test;
import com.atjava.spring5.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author lv
* @create 2021-12-09 23:34
*/
public class TestSpring5 {
@Test
public void testSpring () {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
/**
* com.atjava.spring5.service.UserService@22635ba0
* add userService ...
* userDaoImpl2 add...
*/
}
}
@Resource:根据类型注入 或 根据名称注入
- @Resource 是 java的扩展包 javax中的功能,Spring建议使用 Autowired 和 Qualifier;import javax.annotation.Resource;
package com.atjava.spring5.service;
import com.atjava.spring5.dao.UserDao;
import com.atjava.spring5.dao.UserDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
// @Resource 在 java的扩展包中,不是 Spring中的,所以 Spring不建议使用 @Resource
import javax.annotation.Resource;
/**
* @author lv
* @create 2021-12-09 23:28
*/
/**
* 在注解里面 value属性值可以省略不写,
* 默认值为类名称,首字母小写
*/
//@Component(value = "userService") // 此功能与 xml中 <bean id="userService" class="..." /> 类似
@Service(value = "userService")
public class UserService {
/**
* 定义 dao类型属性
* 不需要添加 set方法
* 添加注入属性注解
*/
// @Resource // 根据类型注入,如果同一个接口有多个实现类,那根据类型注入会报错
@Resource(name = "userDaoImpl2") // 根据名称注入
private UserDao userDao;
// public void setUserDao(UserDao userDao) {
// this.userDao = userDao;
// }
public void add() {
System.out.println("add userService ...");
userDao.add();
}
}
package com.atjava.spring5.test;
import com.atjava.spring5.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.annotation.Resource;
/**
* @author lv
* @create 2021-12-09 23:34
*/
public class TestSpring5 {
@Test
public void testSpring () {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
// @Resource(name = "userDaoImpl2") // 根据名称注入
/**
* com.atjava.spring5.service.UserService@4f638935
* add userService ...
* userDaoImpl2 add...
*/
}
}
@Value:注入普通类型属性
package com.atjava.spring5.service;
import com.atjava.spring5.dao.UserDao;
import com.atjava.spring5.dao.UserDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
// @Resource 在 java的扩展包中,不是 Spring中的,所以 Spring不建议使用 @Resource
import javax.annotation.Resource;
/**
* @author lv
* @create 2021-12-09 23:28
*/
/**
* 在注解里面 value属性值可以省略不写,
* 默认值为类名称,首字母小写
*/
//@Component(value = "userService") // 此功能与 xml中 <bean id="userService" class="..." /> 类似
@Service(value = "userService")
public class UserService {
@Value(value = "lv")
private String name;
@Value(value = "123")
private Integer age;
/**
* 定义 dao类型属性
* 不需要添加 set方法
* 添加注入属性注解
*/
// @Resource // 根据类型注入,如果同一个接口有多个实现类,那根据类型注入会报错
@Resource(name = "userDaoImpl2") // 根据名称注入
private UserDao userDao;
// public void setUserDao(UserDao userDao) {
// this.userDao = userDao;
// }
public void add() {
System.out.println("add userService ...");
userDao.add();
}
@Override
public String toString() {
return "UserService{" +
"name='" + name + ''' +
", age=" + age +
", userDao=" + userDao +
'}';
}
}
// UserService{name='lv', age=123, userDao=com.atjava.spring5.dao.UserDaoImpl2@3901d134}