Spring框架核心IOC的使用:IOC的作用+Bean管理+实例化Bean的方式+DI依赖注入
Spring框架合集:
Spring框架核心IOC的使用:IOC的作用+Bean管理+实例化Bean的方式+DI依赖注入
Spring框架核心IOC的使用:配置式开发+注解式开发+纯注解式开发
Spring框架整合junit:包含配置文件的方式以及纯注解开发的方式
maven下载配置可以参考:maven配置
一、项目环境搭建
1.1 新建maven项目
点击新建项目,选择创建一个maven项目
1.2 配置maven
改成本地maven的路径
在pom文件中创建dependencies,在里面可以添加坐标依赖
打开Maven Repository: Search/Browse/Explore (mvnrepository.com)
搜索需要的jar包,添加坐标依赖之后,maven会帮助导入项目需要的资源
在pom文件中添加坐标依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
1.3 配置applicationContext.xml
目录层级
在resources创建配置文件applicationContext.xml
<?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">
</beans>
二、认识IOC
IOC控制反转:将对象的创建反转给spring框架,主要作用就是降低了程序的耦合度
下面通过一个例子,传统方式创建对象和使用IOC的方式创建对象,来简单体会一下IOC
首先在service下创建好需要的类
UserService接口
public interface UserService {
public void hello();
}
UserServiceImpl类
public class UserServiceImpl implements UserService {
@Override
public void hello() {
System.out.println("hello");
}
}
接着在test下的java目录下创建UserServiceTest类进行测试
加入@Test注解是为了让方法运行
其中的run方法是传统创建对象,run1是用springIOC的方式创建对象
public class UserServiceTest {
//传统创建对象方法
@Test
public void run(){
UserService userService = new UserServiceImpl();
userService.hello();
}
//用springIOC的方式创建对象,ioc是一个map key是对象的标识,value是ioc创建的对象
@Test
public void run1(){
//创建spring ioc工厂,加载spring的配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//FileSystemXmlApplicationContext另一种,配置文件在磁盘
//获取bean对象,返回的是Object对象,强转
UserService userService = (UserService) ac.getBean("xx");
//调用方法
userService.hello();
}
}
使用用springIOC的方式创建对象,还要配置applicationContext.xml文件,在beans中加入,创建好ioc工厂之后可以通过id拿到需要的class,通过程序创建类底层是反射
<!-- id:创建类的标识 class:需要创建哪个类-->
<bean id="xx" class="com.service.impl.UserServiceImpl"></bean>
ApplicationContext接口,这个工厂接口,使用该接口可以获取具体的bean对象,该接口下有两个具体的实现类
- ClassPathXmlApplicationContext,加载类路径下的spring配置文件(常用)
- FileSystemXmlApplicationContext,加载本地磁盘下的spring配置文件,项目与配置文件分离管理(不常用)
三、bean管理
3.1 bean中属性的介绍
- id属性:bean起个名字,唯一性,取值要求:必须以字母开始,可以使用字母、数字、连字符、下划线,不能出现特殊字符
- class属性:bean对象的全路径
- scope属性:表示bean对象的作用范围
- singleton:单例(默认)最常用的方式,生命周期跟配置文件一样,加载配置文件,实例创建
- prototype:多例,不是加载配置文件的时候创建实例的,而是获取实例时才创建实例
- request:多例,不常用,应用在web项目中,每次http请求的时候会创建一个新的实例
- session:多例,不常用,应用在web项目中,同一个http session共享一个实例
- init-method:bean对象创建时可以配置一个指定方法并自动调用
- destroy-method:bean对象销毁时可以配置一个指定方法并自动调用
3.2 具体示例
3.2.1 bean对象的生命周期
在UserServiceImpl类中生成构造方法
public UserServiceImpl() {
System.out.println("我创建了");
}
修改applicationContext.xml文件,scope改为singleton
<bean id="xx" class="com.service.impl.UserServiceImpl" scope="singleton"></bean>
修改测试类UserServiceTest中的run1方法,只是加载配置文件,然后运行
@Test
public void run1(){
//创建spring ioc工厂,加载spring的配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//FileSystemXmlApplicationContext另一种,配置文件在磁盘
//获取bean对象,返回的是Object对象,强转
//UserService userService = (UserService) ac.getBean("xx");
//调用方法
//userService.hello();
}
运行结果
然后修改applicationContext.xml,然后运行
<bean id="xx" class="com.service.impl.UserServiceImpl" scope="prototype"></bean>
运行结果
此时并未输出“我创建了”,修改测试类,然后再运行
@Test
public void run1(){
//创建spring ioc工厂,加载spring的配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//FileSystemXmlApplicationContext另一种,配置文件在磁盘
//获取bean对象,返回的是Object对象,强转
UserService userService = (UserService) ac.getBean("xx");
//调用方法
userService.hello();
}
运行结果
从这个例子中可以体会到singleton与prototype生命周期的不同
3.2.2 init-method与destroy-method
修改UserServiceImpl类
public void init(){
System.out.println("init");
}
修改applicationContext.xml
<bean id="xx" class="com.service.impl.UserServiceImpl" init-method="init"></bean>
运行测试类中的run1方法,会发现自动调用了init方法,destroy-method同理
四、实例化bean的三种方式
4.1 无参的构造方法
默认是无参的构造方法(默认方式,基本上都是使用这种)
<bean id="xx" class="com.service.impl.UserServiceImpl" init-method="init" ></bean>
注意:如果构造方法有参数,此时一定要保留无参的构造方法,不然程序会报错
ioc反射底层默认调用的是无参的构造方法
4.2 静态工厂实例化方式
静态工厂实例化方式,好处是可以自己编写业务逻辑
首先创建com.util包,然后创建一个StaticFactory类,在类中我们可以编写业务逻辑,只需要最后返回一个User类
public class StaticFactory {
public static UserService createUs(){
System.out.println("通过静态工厂的方式");
//编写很多业务逻辑 ... ...
return new UserServiceImpl();
}
}
配置applicationContext.xml文件,这里的类是编写业务逻辑的类,方法调用的是createUs,返回需要的类
<bean id="xx" class="com.util.StaticFactory" factory-method="createUs"></bean>
在测试类中运行run1方法
4.3 实例化工厂实例化方式
实例化工厂实例化方式,好处是可以自己编写业务逻辑
在com.util包下创建一个DFactory类
public class DFactory {
public UserService createUs(){
System.out.println("通过实例化工厂的方式");
//编写很多业务逻辑 ... ...
return new UserServiceImpl();
}
}
配置applicationContext.xml文件,先把DFactory交给bean管理,方法调用的是createUs,返回需要的类
<bean id="DFactory" class="com.util.DFactory" ></bean>
<bean id="xx" factory-bean="DFactory" factory-method="createUs"></bean>
运行测试类
@Test
public void run1(){
//创建spring ioc工厂,加载spring的配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//FileSystemXmlApplicationContext另一种,配置文件在磁盘
//获取bean对象,返回的是Object对象,强转
UserService userService = (UserService) ac.getBean("xx");
//调用方法
userService.hello();
}
五、DI依赖注入
Dependency Injection 依赖注入在spring框架负责创建bean对象时,动态的将依赖对象注入到其他bean对象中
可以理解为赋值
5.1 认识DI
在dao层中创建一个接口UserDao,再创建一个实现类UserDaoImpl
public interface UserDao {
public void hello();
}
public class UserDaoImpl implements UserDao {
@Override
public void hello() {
System.out.println("持久层你好");
}
}
然后在service层创建UserService接口,再创建一个实现类UserServiceImpl
public interface UserService {
public void hello();
}
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Override
public void hello() {
System.out.println("业务层你好");
userDao.hello();
}
}
目录结构
此时我们想通过业务层来调用dao层中的方法,在UserServiceImpl创建了一个UserDao的对象,但是如果此时运行的话,会报空指针的错误。因此我们修改一下UserServiceImpl类,里面new一个UserDaoImpl
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void hello() {
System.out.println("业务层你好");
userDao.hello();
}
}
修改之后运行结果
这种赋值的方式就是依赖注入,就是给变量赋值。通过这种方式,业务层可以调用持久层的方法
5.2 依赖注入的方式
5.2.1 属性的set方法注入值的方式
修改UserServiceImpl类,注意这种方式必须有set方法
public class UserServiceImpl implements UserService {
private UserDao userDao;
private String name;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "UserServiceImpl{" +
"userDao=" + userDao +
", name='" + name + '\'' +
'}';
}
@Override
public void hello() {
System.out.println("业务层你好");
userDao.hello();
}
}
修改配置文件applicationContext.xml,此时为name和userDao赋值
<bean id="userDaoImpl" class="com.dao.impl.UserDaoImpl"></bean>
<bean id="xx" class="com.service.impl.UserServiceImpl">
<property name="name" value="lm"></property>
<property name="userDao" ref="userDaoImpl"></property>
</bean>
其中的property标签是为类中的变量赋值
- 简单类型(基本类型+字符串)property标签使用value属性赋值
- 自定义应用类 property标签使用ref属性赋值
先把UserDaoImpl交给IOC工厂管理,等到用时使用ref赋值
在UserServiceTest类中运行run1方法
@Test
public void run1(){
//创建spring ioc工厂,加载spring的配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//FileSystemXmlApplicationContext另一种,配置文件在磁盘
//获取bean对象,返回的是Object对象,强转
UserService userService = (UserService) ac.getBean("xx");
//调用方法
System.out.println(userService);
}
5.2.2 构造方法注入值的方式
修改UserServiceImpl类,注意使用这种方式时要保留类的无参构造方法,因为实例化bean默认调用的是无参的构造方法,如果不保留的话程序报错
public class UserServiceImpl implements UserService {
private UserDao userDao;
private String name;
public UserServiceImpl() {
}
public UserServiceImpl(UserDao userDao, String name) {
this.userDao = userDao;
this.name = name;
}
@Override
public String toString() {
return "UserServiceImpl{" +
"userDao=" + userDao +
", name='" + name + '\'' +
'}';
}
}
修改applicationContext.xml,这里使用的是constructor-arg标签,注意构造方法的赋值要与配置文件中保持一致不能多也不能少,这里的配置文件中是有name和userDao,如果只有name那么构造方法也应该只有name一个参数
<bean id="userDaoImpl" class="com.dao.impl.UserDaoImpl"></bean>
<bean id="xx" class="com.service.impl.UserServiceImpl">
<constructor-arg name="name" value="Jack"></constructor-arg>
<constructor-arg name="userDao" ref="userDaoImpl"></constructor-arg>
</bean>
运行run1方法
六、对其他数据类型的注入
这里使用都是set方法注入值的方式
6.1 对数组的注入
创建CollectionBean类
public class CollectionBean {
private String[] arr;
public void setArr(String[] arr) {
this.arr = arr;
}
@Override
public String toString() {
return "CollectionBean{" +
"arr=" + Arrays.toString(arr) +
'}';
}
}
配置applicationContext.xml文件,为arr赋值
<bean id="cb" class="com.service.CollectionBean">
<property name="arr">
<array>
<value>李明</value>
<value>xiaomi</value>
</array>
</property>
</bean>
在测试类中创建方法,查看结果
@Test
public void run2(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
CollectionBean cB = (CollectionBean) ac.getBean("cb");
System.out.println(cB);
}
6.2 对可变数组的注入
修改CollectionBean类
public class CollectionBean {
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
@Override
public String toString() {
return "CollectionBean{" +
"list=" + list +
'}';
}
}
修改配置文件
<bean id="cb" class="com.service.CollectionBean">
<property name="list">
<list>
<value>李明</value>
<value>xiaomi</value>
</list>
</property>
</bean>
6.3 对map的注入
修改CollectionBean类
public class CollectionBean {
private Map<String,String> map;
public void setMap(Map<String, String> map) {
this.map = map;
}
@Override
public String toString() {
return "CollectionBean{" +
"map=" + map +
'}';
}
}
修改配置文件
<bean id="cb" class="com.service.CollectionBean">
<property name="map">
<map>
<entry key="xiaomi" value="SU7"></entry>
<entry key="byd" value="海豹"></entry>
</map>
</property>
</bean>
6.4 对Properties注入
修改CollectionBean类
public class CollectionBean {
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "CollectionBean{" +
"properties=" + properties +
'}';
}
}
修改配置文件
<bean id="cb" class="com.service.CollectionBean">
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
6.5 对自定义类型的注入
修改CollectionBean类
public class CollectionBean {
private UserService[] userServices;
public void setUserServices(UserService[] userServices) {
this.userServices = userServices;
}
@Override
public String toString() {
return "CollectionBean{" +
"userServices=" + Arrays.toString(userServices) +
'}';
}
}
修改配置文件
<bean id="userS" class="com.service.impl.UserServiceImpl"></bean>
<bean id="cb" class="com.service.CollectionBean">
<property name="userServices">
<ref bean="userS"></ref>
</property>
</bean>
七、多配置文件的加载方式
如果有多个配置文件,如何使用多配置文件开发
1、在主配置文件中使用< import >标签
<import resource="applicationContext2.xml"></import>
2、创建工厂时直接加载多个配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext.xml");