一、IOC
1、Spring框架介绍
- Spring是轻量级的开源的javaEE框架
- Spring有两个核心部分: IOC 和 AOP
- IOC : 控制反转,把创建对象的过程交给Spring进行管理
- AOP: 面向切面,不修改源代码进行功能增强
- Spring特点:
- 方便解耦,简化开发
- AOP编程支持
- 方便程序测试
- 方便和其他框架进行整合
- 方便进行事务操作
- 降低API开发难度
2、导入Spring相关jar包
<dependencies>
<!-- 日志包,并不是Spring中的-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
</dependencies>
3、IOC容器底层原理
- 什么是IOC
- 控制反转,把对象创建和对象之间的调用过程交给Spring进行管理
- 使用IOC的目的就是降低耦合度
- IOC底层原理
- 通过xml解析读取xml配置文件中配置的bean标签,获取到配置的全类名
- Bean工厂类通过反射Class.forName(全类名)创建Class的对象
- 通过一个Bean工厂类将对象返回,完成对象的创建
4、IOC(BeanFactory接口)
-
IOC思想基于IOC容器完成,IOC容器底层就是一个对象工厂
-
Spring提供IOC容器有两种基本方式(两个接口)
- BeanFactory:IOC的基本实现,Spring内部使用的接口,开发人员不建议使用
- 特点:加载配置文件的时候不会创建对象,在获取对象(getBean())才会创建对象
- ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,开发人员使用
- 特点:加载配置文件的时候就会把在配置文件中的对象进行创建
- BeanFactory:IOC的基本实现,Spring内部使用的接口,开发人员不建议使用
-
继承树
5、IOC操作Bean管理
- Bean管理是指两个操作
- Spring创建对象
- Spring为对象注入属性
- Bean管理有两种方式
- 基于xml配置文件方式实现
- 基于注解方式实现
6、基于xml方式的Bean管理
-
创建对象: 在spring的配置文件中使用bean标签,默认调用的是类的无参构造器
<bean id="user" class="day01.domain.User"></bean>
-
注入属性:两种方式注入属性
-
使用通过setter方法注入属性,要求类必须提供setter方法
<!-- 使用setter注入--> <bean id="bookSet" class="day01.domain.Book"> <property name="name" value="三字经"></property> <property name="price" value="23"></property> </bean>
-
通过constructor构造器注入属性,此时不再调用类的无参构造器,创建对象
<!-- 使用构造器注入--> <bean id="bookCon" class="day01.domain.Book"> <constructor-arg name="name" value="史记"></constructor-arg> <constructor-arg name="price" value="34"></constructor-arg> </bean>
-
p命名空间注入,本质上还是setter方法注入,不做解释
-
-
如何给属性注入null等特殊符号
-
注入null值
<!-- 如何给对象注入特殊符号 可以给属性赋一个null值 null标签--> <bean id="bookSpecial" class="day01.domain.Book"> <property name="name"> <null/> </property> </bean>
-
注入特殊符号
<!-- 如何给对象注入 <南京> 这样的字样: 方式一:使用转义字符 > < 方式二:使用 <![CDATA[<南京>]]> --> <bean id="bookSpec" class="day01.domain.Book"> <!-- <property name="name" value="<南京>"></property>--> <property name="name"> <value><![CDATA[<南京>]]></value> </property> </bean>
-
-
如何注入外部bean
-
使用ref进行注入
<!-- Service层对象的创建--> <bean id="userService" class="day01.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"></property> </bean> <!-- Dao层对象的创建--> <bean id="userDao" class="day01.dao.impl.UserDaoImpl"></bean>
-
使用内部bean注入
<!-- 对于对象的注入不仅可以使用ref属性,也可以使用内部bean的方式--> <bean id="emp" class="day01.domain.Emp"> <property name="name" value="Lucy"></property> <property name="gender" value="女"></property> <property name="dept"> <bean class="day01.domain.Dept"> <property name="name" value="科创部"></property> </bean> </property> </bean>
-
使用级联注入
-
-
集合类型怎么注入
<!-- 集合类型的注入--> <bean id="stu" class="day01.domain.Student"> <property name="arr"> <array> <value>数组1</value> <value>数组2</value> </array> </property> <property name="list"> <list> <ref bean="book1"></ref> <ref bean="book2"></ref> <ref bean="book3"></ref> </list> </property> <property name="map"> <map> <entry key="key1" value="value1"></entry> <entry key="key2" value="value2"></entry> </map> </property> <property name="set"> <set> <value>set1</value> <value>set2</value> <value>set3</value> </set> </property> </bean> <bean id="book1" class="day01.domain.Book"> <property name="name" value="java"></property> <property name="price" value="23"></property> </bean> <bean id="book2" class="day01.domain.Book"> <property name="name" value="java"></property> <property name="price" value="23"></property> </bean> <bean id="book3" class="day01.domain.Book"> <property name="name" value="java"></property> <property name="price" value="23"></property> </bean>
7、Spring中Bean的类型
-
普通bean:在配置文件中定义bean类型就是返回类型,上面的都是普通bean
-
工厂bean(FactoryBean) : 通过配置工厂,返回工厂要返回的类型
-
实现步骤:
-
创建类,让这个类实现FactoryBean接口,重写getObject()方法,指定返回的对象
public class CourseFactory implements FactoryBean<Course> { @Override public Course getObject() throws Exception { Course course = new Course(); course.setName("一本书"); return course; } @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return false; } }
-
在配置文件中配置工厂类
<bean id="bean" class="day01.factorybean.CourseFactory"></bean>
-
测试
@Test public void test1(){ ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); Course bean = context.getBean("bean", Course.class); System.out.println(bean); }
-
-
8、Spring中Bean的作用域(scope属性)
scope属性值 | 作用域解释 |
---|---|
scope=“singleton” | 默认值,bean在容器中是单例的 |
scope=“prototype” | bean在容器中是原形的,即是多例的 |
scope=“request” | 一次请求间bean的单例的,很少使用 |
scope=“session” | 一次会话间bean是单例的,很少使用 |
- singleton 和 prototype的区别?
- singleton 是单例的 prototype是多例的
- scope的属性值为singleton时,在加载Spring配置文件的时候就会创建实例对象,而设置scope的属性值为prototype时,在调用getBean()方法时才创建对象
9、Bean的生命周期
- 第一步:调用无参构造器
- 第二步:调用setter方法注入属性
- 第三步:我在bean初始化方法前执行,Bean的后置处理器postProcessBeforeInitialization()方法
- 第四步:调用初始化方法,需要配置
- 第五步:我在bean初始化方法后执行,bean的后置处理器postProcessAfterInitialization()方法
- 第六步:bean正在被使用
- 第七步:调用销毁方法,需要配置
<!-- 配置bean初始化方法和销毁方法需要配置-->
<bean id="lifeBean" class="day01.domain.LifeBean" init-method="initMethod" destroy-method="destroyMethod">
<property name="name" value="生命周期"></property>
</bean>
<!-- bean的后置处理器默认是BeanPostProcessor,要看到效果我们需要自己编写后置处理器实现BeanPostProcessor接口,并配置-->
<bean id="beanPost" class="day01.domain.BeanPost"></bean>
public class LifeBean {
private String name;
public LifeBean() {
System.out.println("第一步:调用无参构造器");
}
public void setName(String name) {
System.out.println("第二步:调用setter方法注入属性");
this.name = name;
}
public void initMethod(){
System.out.println("第四步:调用初始化方法,需要配置");
}
public void userBean(){
System.out.println("第六步:bean正在被使用");
}
public void destroyMethod(){
System.out.println("第七步:调用销毁方法,需要配置");
}
}
后置处理器BeanPost
public class BeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第三步:我在bean初始化方法前执行,Bean的后置处理器");
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第五步:我在bean初始化方法后执行,bean的后置处理器");
return null;
}
}
测试
/**
* 测试bean的生命周期
*/
@Test
public void test2(){
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("application.xml");
LifeBean life = context.getBean("lifeBean", LifeBean.class);
life.userBean();
//关闭容器时bean被销毁
context.close();
}
10、基于xml的自动装配
- bean中有一个属性为autowire完整自动装配属性值指定装配规则
- 属性值为byName : 根据属性名称自动装配
- 属性值为byType : 根据属性类型自动装配
11、基于xml引入外部属性文件
-
以druid数据库连接池为例
-
druid.properties
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/mnyuansql username=root password=1234
-
application.xml 要引入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"> <context:property-placeholder location="classpath:druid.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClassName}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </bean> </beans>
-