1.IOC介绍
- IOC的作用是控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理
- 使用 IOC 目的:为了耦合度降低
- IOC的原理是使用了xml 解析、工厂模式、反射
2.IOC的bean管理
Bean管理是指spring创建对象和注入属性
2.1 基于xml方式的创建对象
2.1.1 基于 xml 方式创建对象
<bean id="user" class="com.spring5.User"></bean>
- 在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建
- 在 bean 标签有很多属性,介绍常用的属性
- id 属性:唯一标识
- class 属性:类全路径(包类路径) - 创建对象时候,默认也是执行无参数构造方法完成对象创建
2.1.2 基于 xml 方式注入属性
DI:依赖注入,就是注入属性
2.1.2.1 第一种注入方式:使用 set 方法进行注入
首先创建类,定义属性和对应的 set 方法
/**
* 演示使用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;
}
}
然后在 spring 配置文件配置对象创建,配置属性注入
<!--2 set方法注入属性-->
<bean id="book" class="com.spring5.Book">
<!--使用property完成属性注入
name:类里面属性名称
value:向属性注入的值
-->
<property name="bname" value="易筋经"></property>
<property name="bauthor" value="达摩老祖"></property>
</bean>
2.1.2.2 使用有参数构造进行注入
/**
* 使用有参数构造注入
*/
public class Orders {
//属性
private String oname;
private String address;
//有参数构造
public Orders(String oname,String address) {
this.oname = oname;
this.address = address;
}
}
<!-- 有参数构造注入属性-->
<bean id="orders" class="com.spring5.Orders">
<constructor-arg name="oname" value="电脑"></constructor-arg>
<constructor-arg name="address" value="China"></constructor-arg>
</bean>
2.1.2.3 注入属性
外部bean(其实是靠set来赋值的)
<!--1 service和dao 对象创建-->
<bean id="userService" class="com.spring5.service.UserService">
<!--注入userDao 对象
name属性:类里面属性名称
ref属性:创建userDao对象bean标签 id值
-->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.spring5.dao.UserDaoImpl"></bean>
内部bean(其实是靠set来赋值的)
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!--设置对象类型属性-->
<property name="dept">
<bean id="dept" class="com.atguigu.spring5.bean.Dept">
<property name="dname" value="安保部"></property>
</bean>
</property>
</bean>
2.1.2.4 xml 注入集合属性
<bean id="stu" class="com.spring5.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类型属性注入-->
<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>
</bean>
<!--创建多个course 对象-->
<bean id="course1" class="com.spring5.collectiontype.Course">
<property name="cname" value="Spring5 框架"></property>
</bean>
<bean id="course2" class="com.spring5.collectiontype.Course">
<property name="cname" value="MyBatis 框架"></property>
</bean>
<!--注入list集合类型,值是对象-->
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
2.1.2.5 工厂bean的形式注入
1、Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)
2、普通 bean:在配置文件中定义 bean 类型就是返回类型
3、工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样
第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型
public class MyBean implements FactoryBean<Course> {
//定义返回bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("abc");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
<bean id="myBean" class="com.spring5.factorybean.MyBean">
</bean>
2.1.2.6 xml 注入其他类型属性
(1)null 值
<!--null值-->
<property name="address">
<null/>
</property>
(2)属性值包含特殊符号
<!--属性值包含特殊符号
1 把<>进行转义 < >
2 把带特殊符号内容写到 CDATA
-->
<property name="address">
<value><![CDATA[<<南京>>]]></value>
</property>
2.2 基于注解创建对象
2.2.1 开启注解
<!--示例1
use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter
context:include-filter ,设置扫描哪些内容
-->
<context:component-scan base-package="com.hanlp" use-default-
filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--示例2
下面配置扫描包所有内容
context:exclude-filter: 设置哪些内容不进行扫描
-->
<context:component-scan base-package="com.hanlp">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
2.2.2 实例化对象
(1)@Component
(2)@Service
(3)@Controller
(4)@Repository
// 上面四个注解功能是一样的,都可以用来创建bean 实例
// 这些注解都是作用在类上,加注在类上后扫描到后会创建默认单例对象
例如:
@Component(value = "userService") //<bean id="userService" class=".."/>
public class UserService {
public void add() {
System.out.println("service add.......");
}
}
2.2.3 注入对象
- @Autowired:根据属性类型进行自动装配
// 第一步 把 service 和 dao 对象创建,在 service 和 dao 类添加创建对象注解
// 第二步 在 service 注入 dao 对象,在 service 类添加 dao 类型属性,在属性上面使用注解
@Service
public class UserService {
//定义dao类型属性
//不需要添加set 方法
//添加注入属性注解
@Autowired
private UserDao userDao;
public void add() {
System.out.println("service add.......");
userDao.add();
}
}
- @Qualifier:根据名称进行注入
//这个@Qualifier 注解的使用,和上面@Autowired 一起使用
//定义dao类型属性
//不需要添加set方法
//添加注入属性注解
@Autowired //根据类型进行注入
@Qualifier(value = "userDaoImpl1") //根据名称进行注入
private UserDao userDao;
- @Resource:可以根据类型注入,可以根据名称注入
//@Resource //根据类型进行注入
@Resource(name = "userDaoImpl1") //根据名称进行注入
private UserDao userDao;
- @Value:注入普通类型属性
@Value(value = "abc")
private String name;
3. 实例是单实例还是多实例
在 Spring 里面,默认情况下,bean 是单实例对象
- scope设置为singleton的时候为单例,默认的时候就是singleton,加载spring配置的时候就会创建单例对象。
- scope设置为prototype的时候为多实例,调用的时候才会创建,每次调用都创建新的实例。
eg:注解形式
@Service
@Scope("prototype")
public class PersonTemplate {
eg:xml形式
<bean id="book" class="com.spring5.Book" scope="singleton">
<property name="list" ref="bookList"></property>
</bean>
4. 生命周期
(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(4)bean 可以使用了(对象获取到了)
(5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
4.1 xml形式
public class Orders {
//无参数构造
public Orders() {
System.out.println("第一步 执行无参数构造创建 bean 实例");
}
private String oname;
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 调用 set 方法设置属性值");
}
//创建执行的初始化的方法
public void initMethod() {
System.out.println("第三步 执行初始化的方法");
}
//创建执行的销毁的方法
public void destroyMethod() {
System.out.println("第五步 执行销毁的方法");
}
}
<bean id="orders" class="com.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="手机"></property>
</bean>
4.2 注解形式
@Service
public class LifeCycleDemo {
@PostConstruct
public void init(){
System.out.println("init");
}
@PreDestroy
public void destroy(){
System.out.println("destroy");
}
}
5. 后置处理器
// (1)创建类,实现接口 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 id="myBeanPost" class="com.spring5.bean.MyBeanPost"></bean>
6. 自动装配
自动装配是根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入
6.1 xml形式
<!-- 根据属性名称自动注入 -->
<!--实现自动装配
bean标签属性 autowire,配置自动装配
autowire属性常用两个值:
byName根据属性名称注入 ,注入值bean的 id值和类属性名称一样
byType根据属性类型注入
-->
<bean id="emp" class="com.spring5.autowire.Emp" autowire="byName">
<!--<property name="dept" ref="dept"></property>-->
</bean>
<bean id="dept" class="com.spring5.autowire.Dept"></bean>
<!-- 根据属性类型自动注入 -->
<!--实现自动装配
bean标签属性 autowire,配置自动装配
autowire属性常用两个值:
byName根据属性名称注入 ,注入值bean的 id值和类属性名称一样
byType根据属性类型注入
-->
<bean id="emp" class="com.spring5.autowire.Emp" autowire="byType">
<!--<property name="dept" ref="dept"></property>-->
</bean>
<bean id="dept" class="com.spring5.autowire.Dept"></bean>
6.2 注解注入
参考 2.2
7. 引入外部资源
7.1 xml引入propertise
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
7.2 注解引入propertise
@PropertySource("classpath:jdbc.properties")
@Configuration
public class PersonAutoConfiguration {