前言
今天开始学习我自己总结的 Java-学习路线 中的《Spring-IOC》,小简从 0 开始学 Java 知识,并不定期更新所学笔记,期待一年后的蜕变吧!<有同样想法的小伙伴,可以联系我一起交流学习哦!>
- 🚩时间安排:预计2天更新完
- 🎯开始时间:04-10
- 🎉结束时间:04-12
- 🍀总结:超时一天!!!
Spring 概述
简介
Spring 是轻量级的开源的JavaEE框架
Spring 可以解决企业应用开发的复杂性
Spring 有两个核心部分:IOC 和 AOP
- IOC:控制反转,把创建对象过程交给 Spring 进行管理
- AOP:面向切面,不修改源代码进行功能增强
特点
- 1、方便解耦,简化开发
- 2、AOP 编程支持
- 3、方便程序测试
- 4、方便和其他框架进行整合
- 5、方便进行事务操作
- 6、降低 API开发难度
优点
轻量级:Spring 在大小和透明性方面绝对属于轻量级的,基础版本的 Spring 框架大约只有2MB。
控制反转(IOC):Spring 使用控制反转技术实现了松耦合。依赖被注入到对象,而不是创建或寻找依赖对象。
面向切面编程(AOP): Spring 支持面向切面编程,同时把应用的业务逻辑与系统的服务分离开来。
容器:Spring 包含并管理应用程序对象的配置及生命周期。
MVC框架:Spring 的 Web 框架是一个设计优良的 Web MVC 框架。
事务管理:Spring 对下至本地业务上至全局业务(JAT)提供了统一的事务管理接口。
异常处理:Spring 提供一个方便的 API 将特定技术的异常转化为一致的、Unchecked异常。
Spring 架构图
Spring 总共大约有 20 个模块, 由 1300 多个不同的文件构成。
快速入门
环境配置
下载 Spring JAR 包
1、查看最新发布版本:https://spring.io/projects/spring-framework#learn(带红色GA标签的)
2、下载对应版本: https://repo.spring.io/release/org/springframework/spring/
下载完成后解压,解压后的文件目录结构如下所示:
.
├── docs #API文档和开发规范
├── libs #开发需要的JAR包和源码
├── license.txt
├── notice.txt
├── readme.txt
└── schema #开发所需要的schema文件
libs 目录中的 JAR 包分为三类
- RELEASE.jar 结尾的是 Spring 框架 class 文件的 JAR 包
- RELEASE-javadoc.jar 结尾的是 Spring 框架 API 文档的压缩包
- RELEASE-sources.jar 结尾的是 Spring 框架源文件的压缩包
整个 Spring 框架由大约 20 个模块组成,该目录下 Spring 为每个模块都提供了这三类压缩包。
下载第三方依赖包
使用 Spring 开发时,除了要使用自带的JAR包外,Spring的核心容器还需要依赖 commons.logging 的JAR包。
- 1、下载 commons-logging-1.2-bin.tar.gz,下载地址:Download Apache Commons Logging
- 2、下载完成后解压,将 commons-logging-1.2.jar 导入项目
导入核心JAR包
在 libs目录中,有四个 Spring 的基础包,分别对应 Spring 核心容器的四个模块。
- spring-core-5.x.x.RELEASE.jar
- spring-beans-5.x.x.RELEASE.jar
- spring-context-5.x.x.RELEASE.jar
- spring-expression-5.x.x.RELEASE.jar
初学者学习 Sping 框架时,只需将 Sping 的 4 个基础包以及 commons-logging-1.2.jar 复制到项目的 lib 目录,并发布到类路径中即可。
.
├── commons-logging-1.2.jar
├── spring-beans-5.3.18.jar
├── spring-context-5.3.18.jar
├── spring-core-5.3.18.jar
└── spring-expression-5.3.18.jar
创建User类
public class User {
public void add(){
System.out.println("add.......");
}
}
创建配置文件bean1.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">
<!--配置User对象创建-->
<bean id="user" class="com.jwt.User"/>
</beans>
编写测试类BeanTest
public class BeanTest {
@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();
}
}
/**
com.jwt.User@6950e31
add.......
**/
IOC概念
IOC(控制反转),把对象创建和对象之间的调用过程,交给 Spring 进行管理
使用IOC目的:为了降低耦合度
IOC底层原理:xml 解析、工厂模式、反射
IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂
Spring 提供 IOC 容器两种实现方式:(两个接口)
1、BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用 ,加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
2、ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用,加载配置文件时候就会把在配置文件对象进行创建,ApplicationContext 接口有实现类
ApplicationContext 接口实现类
- FileSystemXmlApplicationContext :此容器从一个 XML 文件中加载 beans 的定义,必须提供XML Bean 配置文件的全路径名给它的构造函数。
- ClassPathXmlApplicationContext:此容器从一个 XML 文件中加载 beans 的定义,你需要正确设置 classpath 容器将在 classpath 里找 bean 配置。
IOC操作Bean管理
Bean管理指的是两个操作
- 1、Spring 创建对象
- 2、Spirng 注入属性
Bean管理操作有两种方式
- 1、基于 xml 配置文件方式实现
- 2、基于注解方式实现
Spring 有两种类型 Bean,一种是普通 Bean,另外一种是工厂 Bean(FactoryBean)
普通Bean
在配置文件中定义bean类型就是返回类型
public class MyBean {
}
<!--普通bean-->
<bean id="myBean" class="com.jwt.MyBean"></bean>
@Test
public void testBean() {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
MyBean bean = context.getBean("myBean", MyBean.class);
System.out.println(bean);
}
//com.jwt.MyBean@49c43f4e
工厂Bean
工厂Bean:在配置文件定义 bean 类型可以和返回类型不一致
第一步:创建类,让这个类作为工厂Bean,实现接口FactoryBean
第二步:实现接口里面的方法,在实现的方法中定义返回的Bean类型
public class MyBean implements FactoryBean<Course> {
// 定义返回Bean类型的对象
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("工厂bean");
return course;
}
// 得到对象类型
@Override
public Class<?> getObjectType() {
return null;
}
// 是否是单例模式
@Override
public boolean isSingleton() {
return false;
}
}
<!--工厂bean-->
<bean id="myBean" class="com.jwt.MyBean"></bean>
@Test
public void testFactoryBean() {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
Course bean = context.getBean("myBean", Course.class);
System.out.println(bean);
}
//Course{cname='工厂bean'}
Bean作用域
在 Spring 里面,设置创建 Bean 实例是单实例还是多实例,默认情况下,Bean 是单实例对象
证明:创建二个 Bean 的实例对象,实例对象的地址相同说明是同一对象,也就是 Bean 是单例对象
<bean id="book" class="com.jwt.ioc.Book">
<property name="bname" value="小明"></property>
<property name="bauthor" value="小简"></property>
</bean>
@Test
public void test() {
ApplicationContext context =
new ClassPathXmlApplicationContext ("bean3.xml") ;
Book book1 = context.getBean("book" , Book.class);
Book book2 = context.getBean("book" , Book.class);
System.out.println (book1);
System.out.println (book2);
}
/**相同
com.jwt.ioc.Book@548ad73b
com.jwt.ioc.Book@548ad73b
**/
如何设置单实例还是多实例
在 Spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例
scope 属性值
- singleton,默认值,表示是单实例对象
- prototype,表示是多实例对象
singleton和prototype区别
singleton 表示单实例,prototype 表示多实例。
设置 scope 为 singleton 的时候,在加载 Spring 配置文件时候就会创建单实例对象,
如果 scope 为 prototype 的时候,不是在加载 Spring 配置文件的时候创建对象,而是在调用 getBean 方法的时候创建多实例对象
<bean id="book" class="com.jwt.ioc.Book" scope="prototype">
<property name="bname" value="小明"></property>
<property name="bauthor" value="小简"></property>
</bean>
@Test
public void test() {
ApplicationContext context =
new ClassPathXmlApplicationContext ("bean3.xml") ;
Book book1 = context.getBean("book" , Book.class);
Book book2 = context.getBean("book" , Book.class);
System.out.println (book1);
System.out.println (book2);
}
/**不相同
com.jwt.ioc.Book@eb21112
com.jwt.ioc.Book@2eda0940
**/
Bean生命周期
Bean生命周期:从对象创建到对象销毁的过程
- 1、通过构造器创建 bean 实例(无参数构造)
- 2、为 bean 的属性设置值和对其他 bean 引用(调用set方法)
- 3、调用 bean 的初始化的方法(需要进行配置初始化的方法)
- 4、bean 可以使用了(对象获取到了)
- 5、当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
演示Bean生命周期
public class Orders {
private String oname;
public Orders() {
System.out.println("第一步 执行无参构造器创建bean实例");
}
public void setOname(String oname) {
System.out.println("第二步 调用set方法设置属性值");
this.oname = oname;
}
// 创建执行的初始化方法
public void initMethod() {
System.out.println("第三步 执行初始化方法");
}
// 创建执行的销毁方法
public void destroyMethod(){
System.out.println("第五步 执行销毁方法");
}
}
<!--bean声明周期-->
<bean id="orders" class="com.jwt.ioc.Orders" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="电脑"/>
</bean>
@Test
public void testBeanLive() {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean5.xml");
Orders bean = context.getBean("orders", Orders.class);
System.out.println("第四步 获取创建bean实例的对象"+bean);
context.close();// 手动让bean销毁
}
/**
第一步 执行无参构造器创建bean实例
第二步 调用set方法设置属性值
第三步 执行初始化方法
第四步 获取创建bean实例的对象com.jwt.ioc.Orders@954b04f
第五步 执行销毁方法
**/
如果有bean后置处理器,则bean的生命周期有七种
1、通过构造器创建 bean 实例(无参数构造)
2、为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
3、把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization
4、调用 bean 的初始化的方法(需要进行配置初始化的方法)
5、把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
6、bean 可以使用了(对象获取到了)
7、当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
配置后置处理器,实现 BeanPostProcessor 接口
public class MyBeanPost 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;
}
}
<!--配置后置处理器 配置之后会为所有的bean实例添加后置处理器-->
<bean id="myBeanPost" class="com.jwt.ioc.MyBeanPost"></bean>
@Test
public void testBeanLive() {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean5.xml");
Orders bean = context.getBean("orders", Orders.class);
System.out.println("第四步 获取创建bean实例的对象"+bean);
context.close();// 手动让bean销毁
}
/**
第一步 执行无参构造器创建bean实例
第二步 调用set方法设置属性值
在初始化之前执行的方法
第三步 执行初始化方法
在初始化之后执行的方法
第四步 获取创建bean实例的对象com.jwt.ioc.Orders@481a15ff
第五步 执行销毁方法
**/
基于xml方式
基于xml创建对象
1、在spring配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建
2、在bean标签有很多属性,常用的属性:
- id属性:唯一标识
- class属性:类全路径(包类路径)
3、创建对象时候,默认也是执行无参数构造方法完成对象创建
<!--配置User对象创建-->
<bean id="user" class="com.jwt.User"></bean>
基于xml注入属性
基于 xml 注入属性就是依赖注入(DI)
1、使用set方法进行注入
Step1:创建类,定义属性和对应的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;
}
@Override
public String toString() {
return "Book{" +
"bname='" + bname + '\'' +
", bauthor='" + bauthor + '\'' +
'}';
}
}
Step2:配置xml文件创建对象,用 property 标签注入属性
<bean id="book" class="com.jwt.ioc.Book">
<!--使用property完成属性注入
name:类里面属性名称
value:向属性注入的值 -->
<property name="bname" value="Java入门到精通"></property>
<property name="bauthor" value="小简"></property>
</bean>
Step3:测试
public class BookTest {
@Test
public void test(){
//1 加载 spring 配置文件
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean2.xml");
//2 获取配置创建的对象
Book book = context.getBean("book", Book.class);
System.out.println(book);
}
}
//Book{bname='Java入门到精通', bauthor='小简'}
2、使用有参数构造进行注入
Step1:创建类,定义属性,创建属性对应有参数构造方法
public class Order {
private String oname;
private String address;
public Order(String oname, String address) {
this.oname = oname;
this.address = address;
}
@Override
public String toString() {
return "Order{" +
"oname='" + oname + '\'' +
", address='" + address + '\'' +
'}';
}
}
Step2:配置xml文件创建对象
<bean id="order" class="com.jwt.ioc.Order">
<!--通过属性名称注入-->
<constructor-arg name="oname" value="电脑"></constructor-arg>
<constructor-arg name="address" value="China"></constructor-arg>
<!--通过索引名称注入-->
<!--<constructor-arg index="0" value="平板"></constructor-arg>-->
<!--<constructor-arg index="1" value="china"></constructor-arg>-->
</bean>
Step3:测试
public class OrderTest {
@Test
public void test(){
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean2.xml");
Order order = context.getBean("order", Order.class);
System.out.println(order);
}
}
//Order{oname='电脑', address='China'}
p名称空间注入
使用p名称空间注入,可以简化基于 xml 配置方式
Step1:添加p名称空间到配置文件中xmlns:p="http://www.springframework.org/schema/p"
<?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">
</beans>
Step2:通过p标签进行属性注入
<bean id="book" class="com.jwt.ioc.Book" p:bname="Spring入门" p:bauthor="无名氏"></bean>
注入空值和特殊符号
设置空值:在属性property里使用null标签实现
<bean id="book" class="com.jwt.ioc.Book">
<property name="bname" value="Spring学习"/>
<!--设置null值-->
<property name="bauthor">
<null></null>
</property>
</bean>
<!--Book{bname='Spring学习', bauthor='null'}-->
设置特殊符号:在属性property里使用 value 标签通过 <![CDATA[xxx]]> 实现
<bean id="book" class="com.jwt.ioc.Book">
<property name="bname" value="Spring学习"/>
<property name="bauthor">
<value><![CDATA[<<西游记>>]]></value>
</property>
</bean>
<!--Book{bname='Spring学习', bauthor='<<西游记>>'}-->
注入外部bean
场景:service层调用dao层
Step1:创建两个类 service类和dao类
package com.jwt.Service;
import com.jwt.dao.UserDao;
import com.jwt.dao.UserDaoImpl;
public class UserService {//service类
//创建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();
this.userDao.update();//调用dao方法
}
}
package com.jwt.dao;
public interface UserDao {
public void update();
}
package com.jwt.dao;
public class UserDaoImpl implements UserDao {//dao类
@Override
public void update() {
System.out.println("dao update...........");
}
}
Step2:在spring配置文件中进行配置,使用属性property的ref注入外部对象
<!--service和dao对象创建-->
<bean id="userService" class="com.jwt.Service.UserService">
<!--注入userDao对象
name属性:类里面的属性名称
ref属性:创建userDao对象bean标签id值
-->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.jwt.dao.UserDaoImpl"></bean>
Step3:测试
package com.jwt.testdemo;
public class BeanTest {
@Test
public void test(){
//1 加载 spring 配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("bean2.xml");
//2 获取配置创建的对象
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
}
/**
service add...............
dao update...........
**/
注入内部bean和级联赋值
(1)一对多关系:部门和员工,一个部门有多个员工,一个员工属于一个部门
(2)在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示
Step1:创建部门和员工类
public class Department {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "Department{" +
"dname='" + dname + '\'' +
'}';
}
}
public class Employee {
private String ename;
private String gender;
//员工属于某一个部门,使用对象形式表示
private Department dept;
public Department getDept() {//级联注入第二种需要这个方法
return dept;
}
public void setDept(Department dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Employee{" +
"ename='" + ename + '\'' +
", gender='" + gender + '\'' +
", dept=" + dept +
'}';
}
}
Step2:在 spring配置文件中进行配置
- 第一种写法:内部bean(在bean里面嵌套bean)
<bean id="emp" class="com.jwt.ioc.Employee">
<!--设置两个普通属性-->
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!--设置对象类型属性-->
<property name="dept">
<bean id="dept" class="com.jwt.ioc.Department">
<property name="dname" value="安保部"></property>
</bean>
</property>
</bean>
- 第二种写法:ref级联赋值1
<!--级联赋值-->
<bean id="emp" class="com.jwt.ioc.Employee">
<!--设置两个普通属性-->
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!--级联赋值-->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.jwt.ioc.Department">
<property name="dname" value="财务部"></property>
</bean>
- 第三种写法:ref级联赋值2
<!--级联赋值-->
<bean id="emp" class="com.jwt.ioc.Employee">
<!--设置两个普通属性-->
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!--级联赋值-->
<property name="dept" ref="dept"></property>
<property name="dept.dname" value="技术部"></property>
</bean>
<bean id="dept" class="com.jwt.ioc.Department">
<property name="dname" value="财务部"></property>
</bean>
Step3:测试
public class BeanTest {
@Test
public void test2(){
//1 加载 spring 配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("bean4.xml");
//2 获取配置创建的对象
Employee emp = context.getBean("emp", Employee.class);
System.out.println(emp);
}
}
//写法1:Employee{ename='lucy', gender='女', dept=Department{dname='安保部'}}
//写法2:Employee{ename='lucy', gender='女', dept=Department{dname='财务部'}}
//写法3:Employee{ename='lucy', gender='女', dept=Department{dname='技术部'}}
注入集合类型属性
Step1:创建类,定义数组、list、set、map类型属性,生成对应set方法
package com.jwt.ioc;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Stu {
//1 数组类型属性
private String[] courses;
// 2 list集合类型属性
private List<String> list;
// 3 set集合类型属性
private Set<String> sets;
// 4 map集合类型属性
private Map<String, String> maps;
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
@Override
public String toString() {
return "Stu{" +
"courses=" + Arrays.toString(courses) +
", list=" + list +
", maps=" + maps +
", sets=" + sets +
'}';
}
}
Step2:在spring配置文件进行配置
<bean id="stu" class="com.jwt.ioc.Stu">
<!--数组类型属性注入-->
<property name="courses">
<array>
<value>Spring课程</value>
<value>Mybatis课程</value>
</array>
</property>
<!--list类型属性注入-->
<property name="list">
<list>
<value>测试1</value>
<value>测试2</value>
</list>
</property>
<!--set类型属性注入-->
<property name="sets">
<set>
<value>data1</value>
<value>data2</value>
</set>
</property>
<!--map类型属性注入-->
<property name="maps">
<map>
<entry key="语言1" value="Java"></entry>
<entry key="语言2" value="C++"></entry>
</map>
</property>
</bean>
Step3:测试
public class BeanTest {
@Test
public void test(){
//1 加载 spring 配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("bean5.xml");
//2 获取配置创建的对象
Stu stu = context.getBean("stu", Stu.class);
System.out.println(stu);
}
}
//Stu{courses=[Spring课程, Mybatis课程], list=[测试1, 测试2], maps={语言1=Java, 语言2=C++}, sets=[data1, data2]}
集合注入对象类型
一个学生有多门课程
package com.jwt.ioc;
import java.util.List;
public class Stu{
private List<Course> courseList;
public void setCourseList(List<Course> courseList) {
this.courseList = courseList;
}
@Override
public String toString() {
return "Stu{" +
"courseList=" + courseList +
'}';
}
}
package com.jwt.ioc;
public class Course {
private String cname;
public void setCname(String cname) {
this.cname = cname;
}
@Override
public String toString() {
return "Course{" +
"cname='" + cname + '\'' +
'}';
}
}
在spring配置文件进行配置
<!--创建多个course对象-->
<bean id="course1" class="com.jwt.ioc.Course">
<property name="cname" value="Spring5框架"></property>
</bean>
<bean id="course2" class="com.jwt.ioc.Course">
<property name="cname" value="MyBatis框架"></property>
</bean>
<bean id="stu" class="com.jwt.ioc.Stu">
<!--注入list集合类型,值是对象-->
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
集合注入部分抽取成公共部分
public class Stu{
//list集合类型属性
private List<String> book;
public void setBook(List<String> book) {
this.book = book;
}
@Override
public String toString() {
return "Stu{" +
"book=" + book +
'}';
}
}
Step1:在spring配置文件中引入名称空间 util
<?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:util="http://www.springframework.org/schema/util" <!--添加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 "> <!--添加util名称空间-->
</beans>
Step2:使用util标签完成list集合注入提取
<!--1 提取list集合类型属性注入-->
<util:list id="bookList">
<value>易筋经</value>
<value>九阴真经</value>
<value>九阳神功</value>
</util:list>
<!--2 提取list集合类型属性注入使用-->
<bean id="stu" class="com.jwt.ioc.Stu">
<property name="book" ref="bookList"></property>
</bean>
Step2:测试
public class BeanTest {
@Test
public void test(){
//1 加载 spring 配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("bean5.xml");
//2 获取配置创建的对象
Stu stu = context.getBean("stu", Stu.class);
System.out.println(stu);
}
}
//Stu{book=[易筋经, 九阴真经, 九阳神功]}
XML自动装配
什么是自动装配:根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入
实现自动装配:使用 Bean 标签属性 autowire,配置自动装配 autowire 属性常用两个值:
- byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样
- byType 根据属性类型注入
1、根据属性名称自动注入
<bean id="empAuto" class="com.jwt.ioc.Employee" autowire="byName"></bean>
<bean id="deptAuto" class="com.jwt.ioc.Department"></bean>
2、根据属性类型自动注入
<bean id="empAuto" class="com.jwt.ioc.Employee" autowire="byType"></bean>
<bean id="deptAuto" class="com.jwt.ioc.Department"></bean>
引入外部配置文件
场景:配置 druid 数据库连接池
方式一:直接配置数据库信息
1、引入Druid连接池依赖 jar 包
下载地址:https://repo1.maven.org/maven2/com/alibaba/druid/
2、配置Druid(德鲁伊)连接池
<!--直接配置连接池-->
<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>
方式二:引入外部配置文件
1、创建外部属性文件 druid.properties,写数据库信息
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/dbname
prop.username=root
prop.password=root
2、引入 context 名称空间
xmlns:context="http://www.springframework.org/schema/context"和http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
<?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>
3、把外部 properties 属性文件引入到 Spring 配置文件中 ,${}
取值
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:druid.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>
基于注解方式
什么是注解
- 注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…)
- 使用注解,注解作用在类上面,方法上面,属性上面
- 使用注解目的:简化xml配置
Spring 提供注解
- @Component
- @Service
- @Controller
- @Repository
上面四个注解功能是一样的,都可以用来创建bean实例
@Service一般用在service层,@Controller一般用在web层,@Repository一般用在dao层
基于注解方式创建对象
Step1:引入依赖 spring-aop-5.3.18.jar
Step2:开启组件扫描
- 如果扫描多个包,多个包使用逗号隔开
- 或者扫描该包的上层目录(推荐)
<!--先引入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/context/spring-context.xsd">
</beans>
<!--再开启组件扫描-->
<context:component-scan base-package="com.jwt.annotation"/>
Step3:创建类,在类上面添加创建对象注解
@Service(value = "userService")
public class UserService {
public void add() {
System.out.println("annotation service add ...");
}
}
在注解里面 value 属性值可以省略不写,默认值是类名称,首字母小写即UserService-->userService
注解配置等同xml这段配置<bean id="userService" class="...">
组件扫描配置
<!--开启组件扫描-->
<context:component-scan base-package="com.jwt"/>
上面表示会扫 base-package 下的所有注解,如何配置在 base-package 下哪些类扫描,哪些类不扫描?
配置组件扫描配置的参数:
use-default-filters=”false” 表示现在不使用默认 filter,采用自己配置 filter
context:include-filter 设置扫描哪些内容
context:exclude-filter 设置哪些内容不进行扫描
1、只扫描 base-package下带 Controller 的注解
<context:component-scan base-package="com.jwt" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
2、不扫描 base-package 下带 Controller 的注解
<context:component-scan base-package="com.jwt">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
基于注解方式注入属性
- @Autowired:根据属性类型进行自动装配
Step1:把service和dao对象创建,在service和dao类添加创建对象注解
@Service(value = "userService")
public class UserService {
public void add() {
System.out.println("annotation service add ...");
}
}
@Repository(value = "userDao")
public class UserDao {
public void add() {
System.out.println("annotation dao add...");
}
}
Step2:在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解
@Service(value = "userService")
public class UserService {
// 注入userDao对象
@Autowired
private UserDao userDao;//不需要添加set方法
public void add() {
userDao.add();//调用dao方法
System.out.println("annotation service add ...");
}
}
Step3:测试
@Test
public void test(){
//1 加载 spring 配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
//2 获取配置创建的对象
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
/**
com.jwt.annotation.UserService@12d4bf7e
annotation dao add...
annotation service add ...
**/
- @Qualifier:根据名称进行注入
这个 @Qualifier 注解的使用,和上面@Autowired 一起使用
使用场景:由于@Autowired注解是按照属性类型进行注入,如果 bean 容器中有多个同一类型的实例对象,就需要使用 @Qualifier 根据实例名称指定注入哪一个实例对象
@Autowired //根据类型进行注入
@Qualifier(value = "userDaoImpl1")//根据名称进行注入
private UserDao userDao;
- @Resource:可以根据类型注入,也可以根据名称注入(javax扩展包中的注解)
import javax.annotation.Resource;
@Resource(name = "userDaoImpl1")
private UserDao userDao;
- @Value:注入普通类型属性
@Value(value = "小明")
private String name;
完全注解开发
Step1:创建配置类,替代 xml 配置文件
@Configuration
: 作为配置类 替代xml配置文件@ComponentScan
: 开启组件扫描
@Configuration
@ComponentScan(basePackages = {"com.jwt"})
public class SpringConfig {
}
Step2:编写测试类
使用AnnotationConfigApplicationContext
加载配置类
@Test
public void test() {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
/**
com.jwt.annotation.UserService@6580cfdd
annotation dao add...
annotation service add ...
**/
注解格式和XML格式混用
由于早起开发的系统大部分都是采用xml的形式配置bean,现在的企业级开发基本上不用这种模式了。但是如果你特别幸运,需要基于之前的系统进行二次开发,这就尴尬了。新开发用注解格式,之前开发的是xml格式。这个时候可不是让你选择用哪种模式的,而是两种要同时使用。spring提供了一个注解可以解决这个问题,@ImportResource
,在配置类上直接写上要被融合的xml配置文件名即可,算的上一种兼容性解决方案,没啥实际意义。
@Configuration
@ImportResource("applicationContext1.xml")
public class SpringConfig {
}
proxyBeanMethods属性
前面用到了@Configuration这个注解,当我们使用AnnotationConfigApplicationContext加载配置类的时候,配置类可以不添加这个注解。但是这个注解有一个更加强大的功能,它可以保障配置类中使用方法创建的bean的唯一性。为@Configuration注解设置proxyBeanMethods属性值为true即可,由于此属性默认值为true,所以很少看见明确书写的,除非想放弃此功能。
@Configuration(proxyBeanMethods = true)
public class SpringConfig {
@Bean
public Cat cat(){
return new Cat();
}
}
下面通过容器再调用上面的cat方法时,得到的就是同一个对象了。注意,必须使用spring容器对象调用此方法才有保持bean唯一性的特性。此特性在很多底层源码中有应用。
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
String[] names = ctx.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
System.out.println("-------------------------");
SpringConfig springConfig = ctx.getBean("springConfig", SpringConfig.class);
System.out.println(springConfig.cat());
System.out.println(springConfig.cat());
System.out.println(springConfig.cat());
}
}
参考
❤️Sponsor
您的支持是我不断前进的动力,如果您恰巧财力雄厚,又感觉本文对您有所帮助的话,可以考虑打赏一下本文,用以维持本博客的运营费用,拒绝白嫖,从你我做起!🥰🥰🥰
支付宝支付 | 微信支付 |