1. IOC的概念及原理
⭐ 什么是IOC?
(1) 控制反转, 就是把对象创建和对象之间的调用过程,交给Spring进行管理。
(2) 使用IOC的目的: 为了降低耦合度——解耦。
(3) 上面的入门案例就是IOC的实现
⭐ IOC底层原理
(1) xml解析、 工厂模式、反射
⭐ IOC(接口)
- IOC思想基于IOC的容器完成,IOC容器底层就是对象工厂
- Spring提供IOC容器实现两种方式:(两个接口)
(1) BeanFactory, IOC容器的基本实现,是Spring内部的使用接口,不提供给开发人员使用。
(2) ApplicationContext:BeanFactory接口的子接口。提供更多强大的功能,一般由开发人员调用使用。- ApplicationContext接口实现类有很多实现类。
2. Bean 管理操作实现的两种方式(xml配置文件实现)
⭐ 什么叫Bean管理?
Bean 管理指的是两个操作—— ☀ Spring创建对象、☀ Spring注入属性
2.1 基于xml方式创建对象
(1) 创建实体类
(2) 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 id="user" class="com.jzq.spring5.pojo.User"></bean>
</beans>
(3) 创建对象时候,默认也是执行☀无参数构造方法完成对象的创建。
2.2 基于xml方式注入属性
DI: 依赖注入,就是注入属性.
(1)使用set方法进行注入.
⭐ 创建对应实体类,以及对应成员属性的set方法
⭐ 这类注入必须有无参构造器
package com.jzq.spring5.pojo;
public class Book {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void show() {
System.out.println(this.getName() + ":" + this.getAge());
}
}
⭐ 在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">
<!-- set 方法注入属性 -->
<bean id="book" class="com.jzq.spring5.pojo.Book">
<!-- 使用property 完成属性注入
name: 类里面属性名称
value: 向属性注入的值
-->
<property name="name" value="天龙八部"></property>
<property name="age" value="15"></property>
</bean>
</beans>
(2) 使用有参构造进行注入
⭐ 创建对应的实体类,要有构造方法
package com.jzq.spring5.pojo;
public class User {
public int age;
public void show() {
System.out.println("hello,spring5");
}
}
⭐ 在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 id="user" class="com.jzq.spring5.pojo.User"></bean>
<!-- set 方法注入属性 -->
<bean id="book" class="com.jzq.spring5.pojo.Book">
<!-- 使用property 完成属性注入
name: 类里面属性名称
value: 向属性注入的值
-->
<property name="name" value="天龙八部"></property>
<property name="age" value="15"></property>
</bean>
<!-- 通过有参构造注入属性 -->
<bean id="orders" class="com.jzq.spring5.pojo.orders">
<constructor-arg name="uuid" value="4d5s45da4sdsa445sa"></constructor-arg>
</bean>
</beans>
(3) 使用p名称空间注入(了解——set实现)
⭐ 使用p名称空间注入,可以简化基于xml配置方式
第一步 添加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">
⭐进行属性注入,在bean标签内进行操作
<bean id="bookp" class="com.jzq.spring5.pojo.Book" p:name="11" p:age="151"></bean>
2.3 xml注入其他类型属性(空值或特殊符号)
⭐1.字面量
(1)null值
<!-- 注入空值 -->
<property name="addree">
<null></null>
</property>
(2)属性包含特殊符号
<!-- 注入特殊符号 -->
<property name="addree">
<value><![CDATA[<<济南>>]]></value>
</property>
2.4 xml注入外部bean
1 . 先写好逻辑层和Mapper层结构
⭐IOC容器创建的UserService对象可以调用UserMapper中操作数据库的方法。
2 . 注意看一下UserService中如何实现UserMapper实现类.
⭐ 通过xml注入(set方式),将UserMapperImpl对象注入到UserService的对象中。因为UserService中的是UserMapper的接口,所以注入实现类对象时,其实是一种多态的形式!具体注入方式看第三条的xml关系。
3 . 配置外部bean注入的xml
⭐ xml注入属性UserService,属性为userMapper。 由于注入的并不是一个值,而是一个对象类型(UserMapper),所以用ref进行绑定,而不是value。其中ref绑定的是一个UserMapperImpl实现类的bean的id值。
<!-- 注入外部bean -->
<bean id="userservice" class="com.jzq.spring5.service.UserService">
<!-- 为它用到的属性注入 -->
<property name="userMapper" ref="userMapperIpml"></property>
</bean>
<bean id="userMapperIpml" class="com.jzq.spring5.mapper.UserMapperImpl"></bean>
2.5 注入属性-内部bean
⭐ 一对多的关系
1.注意两个实体类之间的联系, 每个员工类中都有一个部门成员属性
private int age;
private String name;
Department department;
xml的配置如下
<!--注入内部bean测试-->
<bean id="worker" class="com.jzq.spring5.pojo.Workers">
<property name="name" value="贾俊贤"></property>
<property name="age" value="15"></property>
<property name="department">
<!--注入属性内部bean-->
<bean id="department" class="com.jzq.spring5.pojo.Department">
<property name="name" value="协和部"></property>
</bean>
</property>
</bean>
2.6 级联注入
⭐ 第一种方案
xml如下
<!-- 测试级联注入 -->
<bean id="worker2" class="com.jzq.spring5.pojo.Workers">
<property name="name" value="贾俊贤2"></property>
<property name="age" value="19"></property>
<property name="department" ref="department2"></property>
</bean>
<!-- 外部的级联的类 -->
<bean id="department2" class="com.jzq.spring5.pojo.Department">
<property name="name" value="协和部2"></property>
</bean>
⭐ 第二种方案
这张方案需要设置访问器(get)
public Department getDepartment() {
return department;
}
xml如下
<!-- 测试级联注入 -->
<bean id="worker3" class="com.jzq.spring5.pojo.Workers">
<property name="name" value="贾俊贤3"></property>
<property name="age" value="19"></property>
<property name="department" ref="department3"></property>
<property name="department.name" value="协和部3"></property>
</bean>
<!-- 外部的级联的类 -->
<bean id="department3" class="com.jzq.spring5.pojo.Department">
</bean>
2.7 注入array、list、map、set属性
⭐ 这里只是最简单的元素注入
xml 如下
<bean id="ceshi" class="com.jzq.spring5.popj.TestLei">
<!--测试数组注入属性-->
<property name="array">
<array>
<value>xxx</value>
<value>xxxx</value>
<value>xxxxx</value>
</array>
</property>
<!--测试集合注入属性-->
<property name="list">
<list>
<value>大厦大火傻大个</value>
<value>dsadadssadas</value>
</list>
</property>
<!--测试map注入-->
<property name="map">
<map>
<entry key="姓名" value="xx"></entry>
<entry key="年龄" value="58"></entry>
</map>
</property>
<!--测试set-->
<property name="set">
<set>
<value>大撒大撒单d</value>
<value>dsadsdas</value>
</set>
</property>
</bean>
2.8 注入List对象泛型
⭐ 第一种方式: 这种方式通过 ref链接到对象
<bean id="ceshi" class="com.jzq.spring5.popj.TestLei">
<!--测试集合对象-->
<property name="bookList">
<list>
<ref bean="b1"></ref>
<ref bean="b2"></ref>
</list>
</property>
</bean>
<bean id="b1" class="com.jzq.spring5.popj.Book">
<property name="books">
<list>
<value>d7sad7sad7as7</value>
<value>d7sad7sad7as7</value>
<value>d7sad7sad7as7</value>
</list>
</property>
</bean>
<bean id="b2" class="com.jzq.spring5.popj.Book">
<property name="books">
<list>
<value>233123</value>
<value>d7213231237</value>
<value>d7sad21323127sad7as7</value>
</list>
</property>
</bean>
2.9 集合注入值抽取
⭐ 在spring中引入命名空间util:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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="book">
<value>dasdsadsad</value>
<value>dsadsdsd7s8d7sd8</value>
</util:list>
<!--使用提取出来的list注入值-->
<bean id="books" class="com.jzq.spring5.popj.Book">
<property name="books" ref="book"></property>
</bean>
2.10 工厂bean
通过配置工厂bean返回具体实例
⭐ 工厂类:要实现 FactoryBean 接口
package com.jzq.spring5.popj;
import org.springframework.beans.factory.FactoryBean;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
public class Mybean implements FactoryBean<Book> {
@Override
public boolean isSingleton() {
return false;
}
@Override
public Book getObject() throws Exception {
Book book = new Book();
List<String> list = new ArrayList<>();
list.add("dsaadad");
list.add("dsaadad");
list.add("dsaadad");
book.setBooks(list);
return book;
}
@Override
public Class<?> getObjectType() {
return null;
}
}
xml 配置如下:
<!-- 测试工厂bean -->
<bean id="myBean" class="com.jzq.spring5.popj.Mybean"></bean>
2.11 bean的作用域
⭐ bean是单实例还是多实例?
在Spring中,设置创建的bean实例默认是单实例对象。
⭐ 如何设置bean是单实例还是双实例?
在bean标签内设置scope为singleton为单实例。
设置为prototype为多实例。
⭐ singleton单实例和prototype多实例区别
singleton: 默认, spring加载配置文件就创建实例对象。
prototype: 在调用getBean的时候创建实例对象。
<bean id="books" class="com.jzq.spring5.popj.Book" scope="prototype">
<property name="books" ref="book"></property>
</bean>
2.12 bean的生命周期
⭐ bean的整个运行顺序
- 通过构造器创建bean实例(无参构造)
- 为bean的属性设置值,和对其他bean的引用(调用set方法)
- 如果加了bean的后置处理器: 把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
- 调用bean的初始化方法(需要在bean标签配置初始化参数:init-method )
- 如果加了bean的后置处理器: 把bean实例传递bean后置处理器的方法postProcessAfterInitialization
- bean创建实例(获取到对象)
- 当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的参数:destroy-method)
⭐实体类如下:
package com.jzq.spring5.popj;
public class Orders {
private int uid;
// 运行无参构造
public Orders() {
System.out.println("第一步执行了无参构造");
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
System.out.println("第二步执行了赋值set");
}
public void initMethod() {
System.out.println("第三步执行初始化函数(需要在bean配置)");
}
public void destoryMethod() {
System.out.println("第五步执行了销毁函数(需要在bean配置)");
}
}
⭐ bean的后置处理器类:
package com.jzq.spring5.popj;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化bean前执行(配置了bean后置处理器)");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化bean后执行(配置了bean后置处理器)");
return bean;
}
}
⭐ xml下的bean配置如下:
<bean id="order" class="com.jzq.spring5.popj.Orders" init-method="initMethod" destroy-method="destoryMethod">
<property name="uid" value="7878"></property>
</bean>
<!-- 配置bean的后置处理器 -->
<bean id="myBeanPost" class="com.jzq.spring5.popj.MyBeanPost"></bean>
2.13 xml自动装配
根据装配规则(属性名称或者属性类型) , spring自动将匹配的属性值进行注入
- 根据属性名自动注入
设置autowire参数为byType
<bean id="c2" class="com.jzq.spring5.popj.C2" autowire="byName"></bean>
<bean id="c1" class="com.jzq.spring5.popj.C1"></bean>
<bean id="c3" class="com.jzq.spring5.popj.C1"></bean>
- 根据属性类型自动注入
设置autowire参数为byType
⭐注意参数注入不要有多个相同类型的需要注入的bean
<bean id="c2" class="com.jzq.spring5.popj.C2" autowire="byType"></bean>
<bean id="c1" class="com.jzq.spring5.popj.C1"></bean>
2.14 外部属性文件
例如数据库连接
通过context命名空间引入
⭐db.properties文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://x.x.x.x:3306/mybatis?userSSL=true&useUnicode=true&charaterEncoding=UTF-8"
username="xxxxxxx"
password="xxxxxxxxxx"
⭐ xml引入如下
<?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">
<!--引入外部属性文件-->
<context:property-placeholder location="db.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="username"></property>
<property name="password" value="password"></property>
</bean>
</beans>
3. Bean 管理操作实现的两种方式(基于注解方式实现)
⭐什么是注解?
注解是代码特殊标记,格式: @注解名称(属性名=属性值, …)。
使用注解的地方,注解作用在类上,方法上,属性上。
使用注解目的:简化xml配置
⭐spring针对bean管理中的创建对象提供的注解
- @Component
- @Service
- @Controller
- @Repository
上面的四个注解功能一致,都是用来创建bean实例,只是在不同层去使用!
⭐使用注解应该配置的xml(扫描包)?
配置context
通过<context:component-scan>标签的base-package参数设置扫描的包,多个包的时候可以通过逗号隔开,或者写上层目录包
<?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">
<!--<context:component-scan base-package="com.jzq.ddd.popj, com.jzq.ddd.test"></context:component-scan>-->
<context:component-scan base-package="com.jzq.ddd"></context:component-scan>
</beans>
3.1 bean基于注解创建对象
实体类
@Component(value = “book”) == xml里的 <bean id=“book”>
package com.jzq.ddd.popj;
import org.springframework.stereotype.Component;
@Component(value = "book")
public class Book {
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public void show() {
System.out.println("wxq大傻瓜");
}
}
3.2 组件扫描的配置
默认的 <context:component-scan> 下 是use-default-filters=“true”,支持所有的注解扫描。设置为false时,我们可以自动去配置需要扫描的注解
<context:include-filter> 是扫描某注解
<context:exclude-filter> 是除了某注解外扫描,这里注意不要声明use-default-filters=“false”
<?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">
<!--<context:component-scan base-package="com.jzq.ddd.popj, com.jzq.ddd.test"></context:component-scan>-->
<!--<context:component-scan base-package="com.jzq.ddd"></context:component-scan>-->
<!-- 设置需要扫描的注解 -->
<context:component-scan base-package="com.jzq.ddd" use-default-filters="false">
<!--<context:include-filter> 指的是扫描什么注解-->
<!--<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<context:component-scan base-package="com.jzq.ddd">
<!--<context:exclude-filter> 指的是不扫描什么注解-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
</beans>
3.3 基于注解实现属性注入
⭐ 介绍注解
@AutoWired: 根据属性类型进行自动装配 ⭐ 多个实现类的时候不可以使用。
@Qualifier: 根据属性名称进行注入, 注意要和实现类的注解@Repository(value = “xxx”) 一致。
@Resource: 也可以通过类型注入,也可以通过属性名注入,不是spring的注解,来源于javax.annotation.Resource。
@Value: 注入普通基本类型
⭐ 注意外部类要@Repository(value = “xxx”)注解
package com.jzq.ddd.mapper;
import org.springframework.stereotype.Repository;
@Repository(value = "userMapperImpl01")
public class UserMapperImpl implements UserMapper {
@Override
public void querySql() {
System.out.println("查询到你要的数据了:" );
}
}
⭐ 注入属性注解案例
package com.jzq.ddd.service;
import com.jzq.ddd.mapper.UserMapper;
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.Service;
@Service(value = "userService")
public class UserService {
// 值类型
@Value(value = "书世俗叔叔世俗叔叔")
private String date;
// 根据值类型去注入属性,如果有多个实现类的话这种方式将会报错
@Autowired
@Qualifier(value = "userMapperImpl01")
private UserMapper userMapper;
@Autowired
// 根据属性名称进行注入
// 注意点1: 和@Autowired同时使用
// 注意点2: 实现类要用注解@Repository(value = "c2")
@Qualifier(value = "c2")
private UserMapper userMapper2;
public void show(){
System.out.println(userMapper);
userMapper.querySql();
userMapper2.querySql();
System.out.println(date);
}
}
3.4 全注解开发
配置类
package com.jzq.ddd.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = {"com.jzq.ddd"})
// 这句话实际等于 <context:component-scan base-package="com.jzq.ddd"></context:component-scan>
public class Config {
}
使用时注意: new AnnotationConfigApplicationContext(配置类.class)
@Test
public void test03() {
/*
全部注解开发
*/
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
UserService userService = context.getBean("userService", UserService.class);
userService.show();
}