概念
针对bean的生命周期进行管理的轻量级容器,提供了功能强大IOC、AOP及Web MVC等功能
IOC
控制反转,DI依赖注入,将创建对象的过程交给spring管理
AOP
动态代理,在不修改源码的情况下修改或添加功能
特点
1.方便解耦,简化开发
2.Aop编程支持
3.方便测试
4.方便整合各种框架
5.方便进行事务操作
6.降低javaEE API开发难度(例如jdbc)
入门
创建实体类
package com.zwj.bean;
/**
* @author zwj
* @date 2022/2/14 - 21:27
*/
public class User {
private int id;
private String name;
public void add(){
System.out.println("add被调用...............");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
配置spring配置文件
<?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 class="com.zwj.bean.User" id="user"></bean>
</beans>
使用ClassPathXmlApplicationContext类读取配置文件
package com.zwj;
import com.zwj.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author zwj
* @date 2021/7/11 - 15:16
*/
public class SpringText {
@Test
public void text1(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = context.getBean("user", User.class);
user.add();
}
}
IOC概念和原理
概念
什么是Ioc
1.控制反转,把对象创建和对象调用的过程交给spring进行管理
2.使用ioc目的:降低耦合度
底层原理
xml解析,工厂模式,反射
原理
Ioc过程
Ioc实现(工厂模式)
Ioc底层就是一个对象工厂,Spring提供Ioc容器实现的两种方式
1.BeanFactory
Ioc容器基本实现,Spring内部使用的接口,一般开发人员不使用,加载配置文件时,不会创建对象,使用时才会创建
2.ApplicationContext
BeanFactory的子接口,提供更多的功能,提供给开发人员使用的,加载配置文件,创建对象,使用getBean("id",Class)加载工厂模式返回确定类型的对象
3.ApplicationContext实现类
1) FileSystemApplicationContext(path) //path为绝对路径
2) ClassPathXmlApplicationContext(path) //path 为当前src下的相对路径
Bean管理xml的方式
创建对象
set注入属性(property)
<?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 class="com.zwj.bean.User" id="user">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
</bean>
</beans>
有参构造注入属性(constructor-arg)
# 前提是实体类中要声明相应的构造方法
<!--构造方法注入属性-->
<bean class="com.zwj.bean.User" id="user">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="name" value="张三"></constructor-arg>
</bean>
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"
# 特定的名称空间并不需要定义在一个XSD文件中,它只在Spring内核中存在。p名称空间就是这样,它不需要一个schema定义
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">
<!--set方法注入属性-->
<!-- <bean class="com.zwj.bean.User" id="user">-->
<!-- <property name="id" value="1"></property>-->
<!-- <property name="name" value="张三"></property>-->
<!-- </bean>-->
<!--构造方法注入属性-->
<!-- <bean class="com.zwj.bean.User" id="user">-->
<!-- <constructor-arg name="id" value="1"></constructor-arg>-->
<!-- <constructor-arg name="name" value="张三"></constructor-arg>-->
<!-- </bean>-->
<!--p名称空间set注入属性-->
<bean class="com.zwj.bean.Book" id="book" p:bookName="九阳真经"></bean>
</beans>
c命名空间
和p命名空间类似,用于构造函数注入属性
注入空值和特殊符号
<bean class="com.zwj.bean.Book" id="book" p:bookName="九阳真经">
<!--设置空值-->
<property name="author">
<null/>
</property>
<!--设置特殊字符
1.转移字符 < >
2.使用CDATA
-->
<property name="address">
<value>
<![CDATA[<<南京>>]]> # xml文件中的写法
</value>
</property>
</bean>
注入外部bean
# dao
public class BeanDaoImpl {
public void insert(){
System.out.println("insert bean。。。。。。");
}
}
# service
public class BeanServiceImpl {
private BeanDaoImpl beanDao;
public BeanServiceImpl(BeanDaoImpl beanDao) {
this.beanDao = beanDao;
}
public void add(){
beanDao.insert();
}
}
# xml
<!--注入外部bean-->
<bean id="beanDao" class="com.zwj.dao.BeanDaoImpl"></bean>
<bean id="beanService" class="com.zwj.service.bean.BeanServiceImpl">
<constructor-arg name="beanDao" ref="beanDao"></constructor-arg>
</bean>
注入内部Bean
# 在内部注入bean
<!--内部Bean-->
<bean id="emp" class="com.zwj.bean.Emp">
<property name="empName" value="lucy"></property>
<property name="gender" value="female"></property>
<property name="dept">
<bean id="dept" class="com.zwj.bean.Dept" p:deptName="安保部"></bean>
</property>
</bean>
级联赋值
# 在内部注入bean 级联赋值
<!--内部Bean-->
<bean id="emp" class="com.zwj.bean.Emp">
<property name="empName" value="lucy"></property>
<property name="gender" value="female"></property>
<property name="dept">
<bean id="dept" class="com.zwj.bean.Dept" p:deptName="安保部"></bean>
</property>
</bean>
# 外部bean,级联赋值
<!--级联赋值-->
<bean id="emp" class="com.zwj.bean.Emp">
<property name="empName" value="lucy"></property>
<property name="gender" value="female"></property>
<property name="dept" ref="dept"></property>
<!-- <property name="dept.deptName" value="安保部"></property>--> # 必须有get方法
</bean>
<bean id="dept" class="com.zwj.bean.Dept" p:deptName="安保部"></bean>
数据、集合、map属性类型注入
<bean id="stu" class="com.zwj.bean.Stu">
<!--数组-->
<property name="courses">
<array>
<value>语文</value>
<value>数学</value>
</array>
</property>
<!--list集合-->
<property name="list">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
</list>
</property>
<!--map类型-->
<property name="map">
<map>
<entry key="JAVA" value="java"></entry>
</map>
</property>
<!--list对象类型-->
<property name="courseList">
<list>
<ref bean="course1"></ref>
</list>
</property>
</bean>
<bean id="course1" class="com.zwj.bean.Course">
<property name="courseName" value="语文"></property>
</bean>
提取公共集合
引入名称空间util
<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">
<bean id="course1" class="com.zwj.bean.Course">
<property name="courseName" value="语文"></property>
</bean>
<util:list id="list">
<ref bean="course1"></ref>
</util:list>
Bean管理(FactoryBean)
Spring有两种bean
1.普通Bean:在配置文件中定义的class类型就是返回类型
2.工厂Bean(factoryBean):在配置文件中定义的class类型可以和返回类型不一致, 内置bean
1.创建一个类,作为工程bean,实现接口FactoryBean
2.实现接口的方法,实现的方法中定义返回的bean类型
package com.zwj.bean.factory;
import com.zwj.bean.Course;
import org.springframework.beans.factory.FactoryBean;
/**
* @author zwj
* @date 2022/2/15 - 13:25
*/
public class MyBean implements FactoryBean {
//定义返回的bean
/**
* 使用getBean()方法时,会返回getObject()中返回的对象,用于配置复杂Bean时,xml配置文件不好配置
* 接收对象使用getObject()返回的同类型对象
* */
@Override
public Object getObject() throws Exception {
return new Course();
}
@Override
public Class<?> getObjectType() {
return null;
}
}
<?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 class="com.zwj.bean.factory.MyBean" id="myBean"></bean>
</beans>
//测试工厂bean
@Test
public void factoryBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("factorybean.xml");
Course myBean = context.getBean("myBean", Course.class);
System.out.println(myBean);
}
bean作用域(单例和多例)
1.在spring中,可以设置创建bean实例是单实例还是多实例,默认是单实例对象
使用scope属性设置bean是单例还是多例
# singleton 表示单实例 默认 加载配置文件时会直接创建实例对象
# prototype 表示多实例 每次在调用getBean()方法的时候创建一个新的实例对象
<!--多实例-->
<bean class="com.zwj.bean.Course" id="course" scope="prototype">
<property name="courseName" value="语文"></property>
</bean>
//测试单实例和多实例
@Test
public void simpleBean(){
//默认单实例
ApplicationContext context = new ClassPathXmlApplicationContext("bean-list.xml");
Stu stu1 = context.getBean("stu", Stu.class);
Stu stu2 = context.getBean("stu", Stu.class);
System.out.println(stu1);
System.out.println(stu2);
}
bean生命周期
1.通过构造器创建bean实例(无参构造)
2.为bean属性注入值或对其他bean的引用
3.调用bean的初始化方法(需要进行配置)
4.bean可以使用了
5.当容器关闭时,调用bean的销毁的方法(自己配置)
package com.zwj.bean.life;
/**
* @author zwj
* @date 2022/2/15 - 13:57
*/
public class Order {
private String orderName;
public Order() {
System.out.println("order无参构造被调用......");
}
public void setOrderName(String orderName) {
System.out.println("set方法被调用......");
this.orderName = orderName;
}
//创建初始化执行方法
public void init(){
System.out.println("init方法被执行......");
}
//创建销毁执行方法
public void destroy(){
System.out.println("destroy方法被调用.....");
}
}
<?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 class="com.zwj.bean.life.Order" id="order" init-method="init" destroy-method="destroy"></bean>
</beans>
//测试生命周期
@Test
public void lifeTest(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("life.xml");
context.close();
}
结果
order无参构造被调用......
set方法被调用......
init方法被执行......
destroy方法被调用.....
后置处理器
1.通过构造器创建bean实例(无参构造)
2.为bean属性注入值或对其他bean的引用
3.把bean实例传递bean后置处理器的方法
4.调用bean的初始化方法(需要进行配置)
5.把bean实例传递bean后置处理器的方法
6.bean可以使用了
7.当容器关闭时,调用bean的销毁的方法(自己配置)
继承BeanPostProcessor接口
# 单独创建一个后置处理器的类
package com.zwj.bean.life;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @author zwj
* @date 2022/2/15 - 14:14
*/
public class MyPostProcessor implements BeanPostProcessor {
//init之前执行的后置处理器
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("init前置处理器被执行.....");
return bean;
}
//init之后执行的后置处理器
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("init后置处理器被执行.....");
return bean;
}
}
<!--创建后置处理器-->
<bean class="com.zwj.bean.life.MyPostProcessor" id="myPostProcessor"></bean>
xml自动装配
根据指定装配规则(属性名称或属性类型),spring自动将匹配的属性值进行注入
package com.zwj.bean.autowire;
/**
* @author zwj
* @date 2022/2/15 - 14:20
*/
public class Emp {
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"dept=" + dept.toString() +
'}';
}
}
package com.zwj.bean.autowire;
/**
* @author zwj
* @date 2022/2/15 - 14:20
*/
public class Dept {
private String deptName;
public void setDeptName(String deptName) {
this.deptName = deptName;
}
@Override
public String toString() {
return "Dept{" +
"deptName='" + deptName + '\'' +
'}';
}
}
<?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">
<!--自动在spring容器中寻找对应的对象
byName: 根据属性名称寻找相应名称的对象
byType: 根据属性类型寻找相应类型的对象
-->
<!-- <bean class="com.zwj.bean.autowire.Emp" id="emp" autowire="byType"></bean>-->
<bean class="com.zwj.bean.autowire.Emp" id="emp" autowire="byName"></bean>
<bean class="com.zwj.bean.autowire.Dept" id="dept">
<property name="deptName" value="安保部"></property>
</bean>
</beans>
//测试自动装配
@Test
public void autowire(){
ApplicationContext context = new ClassPathXmlApplicationContext("autowire.xml");
Emp emp = context.getBean("emp", Emp.class);
System.out.println(emp.toString());
}
外部属性文件
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
</dependencies>
jdbc.url=jdbc:mysql://localhost:3306/guli?serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=root
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--引入外部配置文件 placeholder 占位符-->
<context:property-placeholder location="classpath:info.properties"/>
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
</beans>
注解创建对象
Spring针对Bean管理中创建对象提供注解
1.@Component
2.@Service
3.@Controller
4.@Repository
Spring自动装配注解
1.@AutoWired 按属性类型装配
2.@Qualifier("") 按属性名称装配,可以指定
3.@Resource(name = "") 默认根据类型进行注入,使用name参数可以设置为名称注入
4.@Value(value="") 注入普通类型,放在普通属性上
1.开启组件扫描(告诉spring哪个包中添加了注解)
<!--开启组件扫描-->
<context:component-scan base-package="com.zwj"/>
package com.zwj.dao;
import org.springframework.stereotype.Repository;
/**
* @author zwj
* @date 2022/2/15 - 14:55
*/
@Repository(value = "userDao")
public class UserDao {
public void add(){
System.out.println("user add");
}
}
package com.zwj.controller;
import com.zwj.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
/**
* @author zwj
* @date 2022/2/15 - 14:57
*/
@Controller
public class UserController {
@Autowired
UserDao userDao;
public void insert(){
userDao.add();
}
}
//测试注解
@Test
public void noteTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("note.xml");
UserController userController = context.getBean("userController", UserController.class);
userController.insert();
}
组件扫描配置
<!-- use-default-filters=false 不使用默认组件扫描 -->
<context:component-scan base-package="com.zwj" use-default-filters="false">
<!--不包含某种规则-->
<!-- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>-->
<!--包含某种规则 与不包含不能同时出现-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>