Spring框架
Spring的Ioc
ioc的含义:一般指控制反转,削减程序间的耦合(削减并非彻底消除)
Spring的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
https://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
<bean>
标签:id
属性对单个bean对象的命名 class
属性定义bean对象的类型、并使用全限定类名。
Spring 的ApplicationContext接口的三大常用实现类
/**
* 获取IOC容器,并根据id获取对象
* ApplicationContext接口的三个常用实现类:
* 1、ClassPathXmlApplicationContext: 加载类路径下的配置文件 要求文件必须在类路径下 不然加载不了(常用)
* 2、FileSystemXmlApplicationContext: 加载任意文件路径的配置文件(要有访问权限)
* 3、AnnotationConfigApplicationContext: 用于读取注解创建容器
* @param args
*/
public static void main(String[] args) {
// 获取核心容器对象 ClassPathXmlApplicationContext实现类
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// 通过getBean方法获取从容器中获取对象
// 方法一:获取对象后强转类型
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
// 方法二:通过getBean重载方法传入该类型的字节码文件获取对象
UserServiceImpl userService = applicationContext.getBean("userService", UserServiceImpl.class);
System.out.println(userDao);
System.out.println(userService);
// 获取核心容器对象 FileSystemXmlApplicationContext实现类 macos下的路径"//"开始
ApplicationContext fileSystemXmlApplicationContext =
new FileSystemXmlApplicationContext("//Users/mfd/Desktop/bean.xml");
UserDaoImpl userDao1 = fileSystemXmlApplicationContext.getBean("userDao", UserDaoImpl.class);
System.out.println(userDao1);
}
Spring的核心容器接口
/*
* Spring核心容器的两个接口ApplicationContext和BeanFactory -- 黑马ssm p94
* ApplicationContext: 单例适用(配置文件中可设置立即加载或延迟加载) 常用
* 它在构建核心容器时,创建对象采取的策略是立即加载,也就是说一加载完配置文件立即创建配置文件中所有对象
* BeanFactory: 多例适用
* 他在创建核心容器时,创建对象采取的策略是延迟加载(LazyLoading),也就是说在加载完配置文件后,什么时候根据id获取
* 对象,什么时候创建该对象。
*/
Spring中Bean的创建细节
Spring创建对象的方式
service层实现类
public UserServiceImpl(String name) { // 非默认构造方法
System.out.println("对象已创建");
}
factory.InstanceFactory(普通工厂类)
public class InstanceFactory {
public UserServiceImpl getUserService() {
return new UserServiceImpl()
}
}
factory.StaticFactory(静态工厂类)
public class StaticFactory {
public static UserServiceImpl getUserService() {
return new UserServiceImpl();
}
}
创建方式一:默认构造
<!--方法一:使用默认构造方法创建当bean标签只有id和class属性时采用的时默认构造方法创建对象。-->
<bean id="userService" class="cn.bilibili.service.impl.UserServiceImpl"/>
注意:若该类没有默认构造方法则创建失败(No matching constructor found in class 'UserServiceImpl)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SwFRFcIP-1606123718297)(/Users/mfd/Java/笔记/笔记图片/无默认构造.png)]
创建方式二:普通工厂
<!--方法二:使用普通工厂中的方法创建对象(使用类的某个方法创建对象,存入Spring的容器中)-->
<bean id="instanceFactory" class="cn.bilibili.factory.InstanceFactory"/>
<!-- factory-bean指定工厂类的id-->
<!-- factory-method指定工厂类的方法-->
<bean id="userService" factory-bean="instanceFactory" factory-method="getUserService"/>
创建方式三:工厂类静态方法
<!--方法三:使用工厂中的静态方法创建对象,(使用类的某个静态方法创建对象、存入Spring容器中)
class属性指定工厂类的全限定类名
factory-method属性指定工厂类中创建该对象的方法
-->
<bean id="userService" class="cn.bilibili.factory.StaticFactory" factory-method="getUserService"/>
Spring中Bean对象作用范围
Spring创建的Bean对象默认是单例的
Spring配置文件中</bean>
标签下的scope
属性用来设置Bean对象的作用范围;
singleton
:单例模式(Spring默认值)
prototype
:多例模式
request
:作用于web应用的请求范围
session
:作用于web应用的会话范围
global-session
:作用与服务器集群环境中的session(全局session),在非集群环境中相当于session
例如:
<bean id="userService" class="cn.bilibili.service.impl.UserServiceImpl" scope="prototype"/>
Spring中Bean对象生命周期
1、singleton:(单例)单例对象和容器生命周期相同
出生:随着核心容器的创建而创建
活着:在容器销毁前一直存在
死亡:在容器销毁时销毁
2、prototype:(多例)
出生:在核心容器创建后,随着使用而创建
活着:对象只要在使用就一直存在
死亡:当对象长时间不用,且没有被引用会根据JVM虚拟机垃圾回收机制自动销毁
public UserServiceImpl() {
System.out.println("对象已创建");
}
@Override
public void addUser() {
System.out.println("保存方法执行了。。。。。");
}
public void init() {
System.out.println("初始化方法执行了。。。。。");
}
public void destroy() {
System.out.println("销毁方法执行了。。。。。。");
}
<bean id="userService" class="cn.bilibili.service.impl.UserServiceImpl" scope="prototype"
init-method="init" destroy-method="destroy"/>
单例模式执行结果:
多例模式执行结果
Spring的依赖注入
依赖注入:当类用到的对象都交给Spring来管理(依赖管理),这些依赖关系的管理称之依赖注入。
方式一:使用构造方法注入
<bean id="userService" class="cn.bilibili.service.impl.UserServiceImpl">
<constructor-arg name="name" value="test"/>
<constructor-arg name="age" value="19"/>
<constructor-arg name="birthday" ref="date"/>
</bean>
<bean name="date" class="java.util.Date"/>
constructor-arg标签的属性:
type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始
name:用于指定给构造函数中指定名称的参数赋值(常用的)
=============以上三个用于指定给构造函数中哪个参数赋值==========================
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
优势:
在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。
弊端:
改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。
方式二:set方法注入–更常用
<bean id="userService2" class="cn.bilibili.service.impl.UserServiceImpl2">
<property name="name" value="test"/>
<property name="age" value="20"/>
<property name="birthday" ref="date"/>
</bean>
set标签中的属性
name:用于指定set方法的名称(set方法去掉set首字母小写)
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
优势:
创建对象时没有明确的限制,可以使用默认构造方法。
劣势:
由于使用set方法设置属性,可能会导致set方法没有执行,从而属性没有值。
方法三:注解注入
持续更新中。。。。
复杂类型/集合类型注入
public class UserServiceImpl3 implements UserService {
private String[] myStr;
private List<String> myList;
private Set<String> mySet;
private Map<String, String> myMap;
private Properties myProps;
// 省略所有属性的set方法。。。。
public void show() {
System.out.println(Arrays.toString(myStr));
System.out.println(myList);
System.out.println(mySet);
System.out.println(myMap);
System.out.println(myProps);
}
}
<bean id="userService3" class="cn.bilibili.service.impl.UserServiceImpl3">
<property name="myStr">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
<property name="myList">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
<property name="mySet">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
<property name="myMap">
<map>
<entry key="TestA" value="A"/>
<entry key="TestB" value="B"/>
</map>
</property>
<property name="myProps">
<props>
<prop key="TestC">C</prop>
<prop key="TestD">D</prop>
</props>
</property>
</bean>
运行结果:
[AAA, BBB, CCC]
[AAA, BBB, CCC]
[AAA, BBB, CCC]
{TestA=A, TestB=B}
{TestD=D, TestC=C}
Spring使用注解创建对象
用于创建对象的
他们的作用就和在xml配置文件中编写一个<bean>标签实现的功能一样
"@Component"注解相当于bean标签什么都不写id属性默认是首字母小写的类名(可用value属性更改)
"@Controller":一般用于表现层
"@Service":一般用于业务层
"@Repository":一般用于持久层层
此三个注解在功能上是一摸一样的,是Spring为了让我们更清楚的区别三层架构
用于注入数据的
他们的作用就和在xml配置文件中编写一个<property>标签实现的功能一样
"@Autowired"
作用:自动按照类型注入,如果ioc容器中有一个bean的类型和要注入的变量类型匹配,则自动注入。
如果ioc容器中没有个bean的类型和要注入的变量类型匹配,则报错。
出现位置:变量上/方法上。
细节:此时的注入set方法就不是必须的了。
"@Qualifier"
作用:在按照类型注入的基础上,按照ioc容器中的bean对象id注入,在注入类成员时不能单独使用,但在注入方法参数时可以单独使用。
属性:value参数用于指定bean的id
"@Resource"
作用:直接按照bean的id注入,可以单独使用
属性:name属性用于指定bean的id
以上三个注解只能用bean对象的注入,而基本类型和String无法注入
并且集合注入只能使用xml
"@Value"
作用:用于给基本数据类型和String类型注入数据
属性:
value: 用于指定数据的值,他可以使用SpEl表达式(Spring的El表达式)
SpEl的写法: ${表达式}获取数据
用于改变作用范围的
他们的作用就和bean标签中使用scope属性实现的功能相同
"@Scope"
作用:用于指定bean的作用范围(单例/多例)
属性:
value:指定取值范围(singleton/prototype)
和生命周期相关
他们的作用和bean标签中使用init-method和destroy-method的作用一样
"@PostDestroy"指定destroy-method
"@PostConstruct"指定init-method
Spring中的新注解
"@Configuration"
作用:表示该类是一个配置类
在作为AnnotationConfigApplicationContext对象的参数时可以省略
"@ComponentScan"
作用:指定Spring创建Ioc核心容器时扫描的包
属性:
value:与basePackages相同用于指定Spring扫描的包名称
"@Bean"
作用:指定将创建对象的方法加入到Spring容器中
属性:
value:用于指定加入容器时的key,不写默认为方法名称。
注意:如果@Bean标注的方法有参数,Spring会在容器中查找名称相同的参数
查找方法和Autowired相同
"@Scope"
作用:用于改变bean对象的对用范围
"@Import"
作用:可以引入其他配置类,此时此类不需要标注Configuration注解,也不需要添加扫描包
/*使用RunWith更改junit的main方法*/
@RunWith(SpringJUnit4ClassRunner.class)
/*使用此注解告知Spring配置类*/
@ContextConfiguration(classes = SpringConfiguration.class)