spring
Spring 官网地址: https://spring.io/
spring基础知识
什么是Spring
Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。
Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。
然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
目的:解决企业应用开发的复杂性
功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
范围:任何Java应用
它是一个容器框架,用来装javabean(java对象),中间层框架(万能胶)可以起一个连接作用,比如说把Struts和hibernate粘合在一起运用。简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
什么是控制反转(或依赖注入) IOC
控制反转 IoC,用白话来讲,就是由容器控制程序之间的(依赖)关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在:(依赖)控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。
Spring的体系结构
Spring 框架采用分层架构,根据不同的功能被划分成了多个模块,这些模块可根据作 用分为 Data Access/Integration、Web、AOP、Aspects、Messaging、Instrumentation、Core Container 和 Test。
Data Access/Integration(数据访问/集成)
数据访问/集成层包括 JDBC、ORM、OXM、JMS 和 Transactions 模块
Web
Spring 的 Web 层由 spring-web、spring-webmvc、spring-websocket 和 spring-webflux 组成。
Core Container(核心容器)
Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上 下文模块和 Expression Language 表达式语言模块组成。
AOP 模块
提供了面向切面编程实现,允许定义方法拦截器和切入点,将代码按 照功能进行分离,以降低耦合性。
Aspects 模块
提供与 AspectJ 的集成,是一个功能强大且成熟的面向切面编程 (AOP)框架。
Instrumentation 模块
提供了类工具的支持和类加载器的实现,可以在特定的应 用服务器中使用。
Test模块
支持 Spring 组件,使用 JUnit 或 TestNG 框架的测试。
Spring 的 jar 包
我们选用5.2.7版本
对上图的不同的文件后缀做出介绍:
-dist 后缀表示该文件夹下存放的是 jar 包,文档和 xsd 文件;
-docs 后缀表示该文件夹下存放相关文档,开发指南和 API;
-schema 里存放了 Spring 所用的 xsd 文件。
libs 目录文件说明:
.RELEASE.jar: 开发时需要引用的 jar
.RELEASE-javadoc.jar: 文档
.RELEASE-sources.jar: 源码
Spring IOC 容器
Spring IOC 容器介绍
IOC 思想 :
是指在程序开发中,对象实例的创建不再由调用者管理,而是 由 Spring 容器创建。Spring 容器会负责控制程序之间的关系,而不是由程序代码直接控制, 因此,控制权由程序代码转移到了 Spring 容器中,控制权发生了反转.
IOC 容器概念 :
IOC 容器就是具有依赖注入功能的容器,IOC 容器负责实例化、定位、配置应用程序中 的对象及建立这些对象间的依赖。
Bean 的概念 :
在 Spring 中,被 Spring 容器所管理的对象称之为”Bean”对象。一个 Spring 的 Bean 对象 可以是任何形式的 POJO。
Spring IOC 容器类型:
Spring 提供了两种 IoC 容器,分别为 BeanFactory 和 ApplicationContext
BeanFactory:
是基础类型的 IOC 容器。简单来说,BeanFactory 就是一个管理 Bean 的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法。
ApplicationContext:
ApplicationContext 是 BeanFactory 的子接口,也被称为应用上下文。 它不仅提供了 BeanFactory 的所有功能, 还添加了对国际化、资源访问、事件传播等方面的良好支持。
ApplicationContext 接口有两个常用的实现类:
Spring IOC 容器的使用
搭建环境
创建项目
创建一个java project项目
添加核心容器的jar包
导入jar包
导入tomcat
选中,然后点击ok
退出到主界面,再次点进去
注意以下箭头指向
出现如下图片所示时,加入tomcat成功
参考文章链接
添加 Spring 配置文件:
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 容器管理 Bean 对象
创建 UsersService 接口与实现类
package com.bjsxt.service;
public interface UsersService {
void addUsers();
}
package com.bjsxt.service.impl;
import com.bjsxt.service.UsersService;
public class UsersServiceImpl implements UsersService {
@Override
public void addUsers() {
System.out.println("UsersService addUsers ......");
}
}
修改配置文件
<?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="usersService" class="com.bjsxt.service.impl.UsersServiceImpl"/>
</beans>
获取 IOC 容器中的对象
package com.bjsxt.test;
import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UsersServiceTest {
public static void main(String[] args) {
/* UsersService usersService = new UsersServiceImpl();
usersService.addUsers();*/
//启动Spring
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取
UsersService usersService = (UsersService) applicationContext.getBean("usersService");
usersService.addUsers();
}
}
可能会报出如下异常
这是因为没有导入common包导致的
我们将common jar包导入,可以得到
Spring IOC 容器创建 Bean 对象的三种方式
通过构造方法去创建Bean对象
我们知道,一个构造方法是和类同名的,当类实例化一个对象的时候,会自动调用构造方法。
通过静态工厂方法创建对象
静态工厂方法是23种设计模式的工厂设计模式当中的一种方法,设计模式的工厂模式可以分为静态工厂和动态工厂。(工厂模式的作用也就是为我们提供了一个创建对象的过程)
什么是静态工厂方法
静态工厂法模式是一种封装对象创建的方法。如果没有工厂方法,只需调用类的构造器(构造方法)直接:Foo x = new Foo()… 创建对象。使用此模式,您可以调用工厂方法:Foo x = Foo.create()… 去创建对象。构造函数被标记为私有函数,因此只能从类内部调用它们,而工厂方法标记为static这样就可以在没有对象的情况下调用它。
为什么使用静态工厂方法
使用静态工厂方法的好处有:
具名、环保、多子
具名:
静态工厂方法有名称
对于构造器来说,根据入参的不同可以有多个构造器,但是这些构造器的名称都是一样的,使用者在调用时就会一头雾水,到底应该调用哪一个呢。
而使用了静态工厂方法之后,你可以根据方法的功能给方法起不同的名字,只有名字起得好,使用者看到方法名就知道是什么意思,知道这时候应该调用哪一个方法,大大提高了代码的可读性。
环保:
不必每次调用的时候都创建一个新对象
使用构造器,每次都会产生一个新的对象。
而静态工厂方法,可以重复地返回预先创建好的对象。
多子:
可以返回原返回类型的任何子类型的对象
使用构造器,你只能返回一种类型的对象。
而使用静态工厂方法,你可以根据需要,返回原返回类型的任何子类型的对象。
正是因为静态工厂方法有着比构造器更大的优势,我们在创建类时,切忌第一反应就是提供公有构造器,要优先考虑静态工厂方法
小结
- 静态工厂方法具有三大优势——具名、环保、多子。
- 如果一个类提供了静态工厂方法,那么也就不需要考虑对这个类进行工厂模式了。
- 我们在创建类时,切忌第一反应就是提供公有构造器,要优先考虑静态工厂方法。
实践
创建静态工厂方法:
package com.bjsxt.factory;
import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;
/**
* 静态工厂方法的实践
* 使用static 意味着,无论我获取多少次getInstance方法,拿到的都是相同的UsersServiceImpl()
*/
public class ObjectFactory {
public static UsersService getInstance(){
return new UsersServiceImpl();
}
}
修改配置文件:
<?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="usersService" class="com.bjsxt.service.impl.UsersServiceImpl"/>
<!--通过静态工厂方法去实例化对象-->
<bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>
</beans>
创建测试类进行测试:
package com.bjsxt.test;
import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ObjectFactoryTest {
public static void main(String[] args){
//启动Spring
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取
UsersService usersService = (UsersService) applicationContext.getBean("usersService2");
usersService.addUsers();
}
}
输出两次Init…,也就是说,构造方法被调用了两次
出现这个结果是因为在配置文件内
我们先调用了UsersServiceImpl类,运行时会执行一次他的构造方法
又因为下方的静态工厂方法的使用,我们调用了一次UsersServiceImpl()方法
所以输出两次Init…
通过动态工厂方法创建对象
什么是动态工厂方法
动态工厂和静态工厂最大的区别是:在创建对象时所返回的对象并不是相同的对象,而是每次调用方法都会产生一个新的对象
怎么使用动态工厂方法
将工厂方法的static去掉即可
实践
创建包含动态工厂的方法
package com.bjsxt.factory;
import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;
public class DynamicObjectFactory {
public UsersService getInstance(){
return new UsersServiceImpl();
}
}
修改配置文件
<!--通过动态工厂方法实例化对象-->
<bean id="dynamicObjectFactory" class="com.bjsxt.factory.DynamicObjectFactory"/>
<bean id="usersService3" factory-bean="dynamicObjectFactory" factory-method="getInstance"/>
创建测试类
package com.bjsxt.test;
import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DynamicFactoryTest {
public static void main(String[] args){
//启动Spring
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取
UsersService usersService = (UsersService) applicationContext.getBean("usersService3");
usersService.addUsers();
}
}
在 Spring IOC 容器中获取 Bean 对象的方式
通过 id 或 name 获取 Bean 对象
格式:applicationContext.getBean(id|name);
配置文件
这里使用name属性:
<bean id="usersService" name="name1,name2,name3" class="com.bjsxt.service.impl.UsersServiceImpl"/>
同时,将其他bean注释
获取 bean 对象
public static void main(String[] args) {
/* UsersService usersService = new UsersServiceImpl();
usersService.addUsers();*/
//启动Spring
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取
UsersService usersService = (UsersService) applicationContext.getBean("name2");
usersService.addUsers();
}
报出的异常
Exception in thread “main” org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘usersService3’ available
这是因为没有将测试文件重新指定为 测试配置文件
异常解除:
通过类型获取 Bean 对象
通过类型来或取 Bean 时,要求类型必须是唯一的。
获取 Bean 对象:
//通过类型获取 Bean 对象
UsersService usersService = applicationContext.getBean(UsersServiceImpl.class); usersService.addUsers();
通过 id 或 name 与类型获取 Bean 对象
在 SpringIOC 容器中,通过类型获取对象时,如果同一类型存在多个对象,我们可以使 用 id 或 name 来识别需要获取的对象。
第一种方法
//启动Spring
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取
UsersService usersService = applicationContext.getBean("name2",UsersServiceImpl.class);
usersService.addUsers();
第二种方法
public static void main(String[] args) {
//启动Spring IOC容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
/*方式二*/
//获取Spring IOC容器中所有的Bean对象的ID
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
//输出Bean对象的所有id
for(String name: beanDefinitionNames){
System.out.println(name);
}
UsersService usersService = applicationContext.getBean(beanDefinitionNames[0],UsersServiceImpl.class);
usersService.addUsers();
}
Spring IOC 容器如何创建对象
如何实例化对象
Spring IOC 容器在启动时默认的会将在配置文件中所配置的所有 Bean 对象立即进行实 例化,并保存在 IOC 容器中。
我们可以通过<bean>标签 lazy-init 属性的实现延迟实例化对象。
注意:lazy-init="false"只对 scope 属性为 singleton 才有效,如果 scope 属性为 pototype, 无论 lazy-init 的属性值是什么,都只在通过 getbean 时进行实例化。
立即创建bean
azy-init=“false”(默认)
在 Spring IOC 容器启动时会实例化配置文件中的所有 Bean 对象。
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" lazy-init="false"/>
<!--通过静态工厂方法去实例化对象-->
<bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>
延迟创建bean
azy-init=“true”
当调用 getBean 方法是创建对象。
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" lazy-init="true"/>
<!--通过静态工厂方法去实例化对象-->
<bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>
Bean 对象的作用域
作用域限定了 Spring Bean 的作用范围,在 Spring 配置文件定义 Bean 时,通过 声明 scope 配置项,可以灵活定义 Bean 的作用范围。
scope 属性的值:
- singleton(默认的值)
- prototype
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" scope="singleton"/>
<!--通过静态工厂方法去实例化对象-->
<bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>
测试类
public class BeanScopeTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("------------------------");
}
}
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" scope="prototype"/>
<!--通过静态工厂方法去实例化对象-->
<bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>
singleton(单例)
singleton 为 scope 属性的默认值。当 scope 属性的值为 singleton 时,Spring IOC 容器启 动时会立即实例化一次 Bean 对象,并一直被 Spring IOC 容器所缓存,所以生命周期较长
配置文件
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" scope="singleton"/>
<!--通过静态工厂方法去实例化对象-->
<bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>
测试类:
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("------------------------");
UsersService usersService = (UsersService) applicationContext.getBean("usersService");
UsersService usersService1 = (UsersService)applicationContext.getBean("usersService");
System.out.println(usersService);
System.out.println(usersService1);
}
两个对象引用的地址是一样的
prototype(多例)
当 scope 属性的值为 prototype 时,每次调用调用 getBean 方法时都会返回一个新的 Bean 对象,Spring IOC 容器并不会缓存该对象,所以就不再负责管理它的生命周期。
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" scope="prototype"/>
<!--通过静态工厂方法去实例化对象-->
<bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>
再次调用测试类,多例的测试类和单例的测试类相同
这是一个对Spring IOC 容器的使用,但我们可以发现,这样做会更加复杂,因此我们在使用的时候,大多数情况下使用的都是Spring IOC的依赖注入。
DI 依赖注入
对于 Spring IOC 容器而言我们更多的是使用它的依赖注入。 Spring 创建对象的过程叫 做 IOC,创建对象时给对象属性赋值叫做 DI,所以我们可以认为 IOC 和 DI 是同一个事情。
什么是依赖注入(DI)
依赖注入是指在 Spring IOC 容器创建对象的过程中,将所 依赖的对象通过配置进行注入。我们可以通过依赖注入的方式来降低对象间的耦合度。
类之间的关系
继承 实现 依赖 关联 聚合 组合
关系强度:继承 = 实现 > 组合 > 聚合 > 关联 > 依赖
我们重点介绍:
依赖关系
是一种使用的关系, 即一个类的实现需要另一个类的协助, 所以要尽量 不使用双向的互相依赖
主要体现在:局部变量 方法的参数或者对静态方法的调用
聚合关系
是整体与部分的关系.如车和轮胎是整体和部分的关系
主要体现在:成员变量
为什么使用依赖注入
有一篇讲的很浅显的文章,跳转链接
依赖注入有如下优点:
开闭原则:
开闭原则的好处是:易于扩展,易于维护
高内聚,低耦合
依赖注入的方式
在使用依赖注入时,如果注入的是 Bean 对象,那么要求注入的 Bean 对象与被注入的 Bean 对象都需要 Spring IOC 容器来实例化。
通过 Set 方法注入
需要为注入的成员变量提供 Set 方法。
示例:
创建持久层
package com.bjsxt.dao;
public interface UsersDao {
void insertUsers();
}
package com.bjsxt.dao.impl;
import com.bjsxt.dao.UsersDao;
public class UsersDaoImpl implements UsersDao {
@Override
public void insertUsers() {
System.out.println("JDBC:....insert into ....");
}
}
修改业务层的UsersServiceImpl类:
public class UsersServiceImpl implements UsersService {
private UsersDao usersDao;
public UsersDao getUsersDao() {
return usersDao;
}
public void setUsersDao(UsersDao usersDao) {
this.usersDao = usersDao;
}
public UsersServiceImpl(){
System.out.println("Init.......");
}
@Override
public void addUsers() {
usersDao.insertUsers();
// System.out.println("UsersService addUsers ......");
}
}
如果不实现set和get方法,usersDao就是空的,会报出空指针异常。
修改配置文件
<bean id="usersDao" class="com.bjsxt.dao.impl.UsersDaoImpl"/>
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl">
<property name="usersDao">
<ref bean="usersDao"/>
</property>
</bean>
SpringIOC启动时,会先去实例化bean对象,会发现id叫usersService的对象内有一个属性叫usersDao,而且这个属性需要注入的是usersDao对象,那么就会将usersDao通过usersServiceImpl类的set方法注入到usersDao对象内,这样usersDao内就不是空的
创建一个测试类
package com.bjsxt.test;
import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DITest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UsersService usersService= (UsersService) applicationContext.getBean("usersService");
usersService.addUsers();
}
}
使用Spring DI进行注入编程的好处是,如果我们要使用Mybatis去替换原有的JDBC,那么我们只需要添加好Mybatis的接口和实现类之后,修改xml内对应的配置即可。
如:
我们在持久层新建一个实现类:
package com.bjsxt.dao.impl;
import com.bjsxt.dao.UsersDao;
public class UsersDaoMybatisImpl implements UsersDao {
@Override
public void insertUsers() {
System.out.println("Mybatis.....insert into.....");
}
}
在原有代码的基础上,我们添加对应的Mybatis的bean对象,将原来的usersDao替换为usersDaoMybatis即可
<bean id="usersDao" class="com.bjsxt.dao.impl.UsersDaoImpl"/>
<!-- 新建一个Mybatis的bean对象 -->
<bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl">
<property name="usersDao">
<ref bean="usersDaoMybaits"/>
</property>
</bean>
通过 构造方法注入
Bean 对象中需要提供有参的构造方法
在配置文件内创建bean对象
<bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl">
<!--
name:根据参数名称识别参数 name="usersDao"
index:根据参数的位置来识别参数 index="0"
type:根据参数的类型识别参数 type="com.bjsxt.dao.UsersDao"
-->
<constructor-
<constructor-arg name="usersDao">
<ref bean="usersDaoMybaits"/>
</constructor-arg>
</bean>
为bean对象提供一个有参的构造方法
private UsersDao usersDao;
public UsersServiceImpl(UsersDao usersDao){
this.usersDao = usersDao;
}
调用测试类
public class DITest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UsersService usersService= (UsersService) applicationContext.getBean("usersService");
usersService.addUsers();
}
}
自动注入(使用方便,后期维护不方便)
自动注入的方式有两种,一种是全局配置自动注入,另一种是局部配置自动注入。
无论全局配置或局部单独配置,都有 5 个值可以选择:
no:当 autowire 设置为 no 的时候,Spring 就不会进行自动注入。
byName:在 Spring 容器中查找 id 与属性名相同的 bean,并进行注入。需要提供 set 方 法。
byType:在 Spring 容器中查找类型与属性名的类型相同的 bean,并进行注入。需要提供 set 方法。
constructor:仍旧是使用 byName 方式,只不过注入的时候,使用构造方式进行注入。
default:全局配置的 default 相当于 no,局部的 default 表示使用全局配置设置。
局部自动注入
通过 bean 标签中的 autowier 属性配置自动注入。
有效范围:仅针对当前 bean 标签生效。
<bean id="usersDao" class="com.bjsxt.dao.impl.UsersDaoImpl"/>
<!-- byName 根据名称去查找对应的bean对象 -->
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" autowire="byName">
</bean>
我们这里有一个usersDao,当autowire="byName"时,我们会将usersDao注入给我们的usersService.usersDao对应的bean对象是UsersDaoImpl
我们将UsersDaoImpl类的属性重新添加上get 和 set 方法
public class UsersServiceImpl implements UsersService {
public UsersDao getUsersDao() {
return usersDao;
}
public void setUsersDao(UsersDao usersDao) {
this.usersDao = usersDao;
}
private UsersDao usersDao;
public UsersServiceImpl(UsersDao usersDao){
this.usersDao = usersDao;
}
public UsersServiceImpl(){
System.out.println("Init.......");
}
@Override
public void addUsers() {
usersDao.insertUsers();
// System.out.println("UsersService addUsers ......");
}
创建一个测试类
public class AutoWireTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UsersService usersService =(UsersService) applicationContext.getBean("usersService");
usersService.addUsers();
}
}
也可以使用Mybatis的bean对象
<bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>
<!-- byName 根据名称去查找对应的bean对象 -->
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" autowire="byName">
</bean>
同理,使用autowire=“constructor” 进行注入
<bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" autowire="constructor"/>
全局自动注入
通过 beans 标签中的 default-autowire 属性配置自动注入。
有效范围:配置文件中的所有 bean 标签都生效。
<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"
default-autowire="byType">
但是,我们的配置文件会报出一个异常
如果我们任然去运行测试类,那么控制台会给出一个报错
我们删除一个bean对象即可
<bean id="usersDao" class="com.bjsxt.dao.impl.UsersDaoImpl"/>
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" />
或者
<!-- 新建一个Mybatis的bean对象 -->
<bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" />
但我们如果使用byName查询自建的Mybaits时,会报出一个空指针的异常
如下:
<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"
default-autowire="byName">
<bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl" />
因为usersServiceImpl类的usersDao并没有注入,所以在addUsers方法内使用usersDao对象去调用的insertUsers(),usersDao本来就是空的,自然会报出空指针异常 。
解决方法:
需要将bean对象的id的名字和注入对象的名称一样
也就是将UsersServiceImpl类的usersDao改为usersDaoMybatis
public class UsersServiceImpl implements UsersService {
private UsersDao usersDaoMybaits;
public UsersDao getUsersDaoMybaits() {
return usersDaoMybaits;
}
public void setUsersDaoMybaits(UsersDao usersDaoMybaits) {
this.usersDaoMybaits = usersDaoMybaits;
}
public UsersServiceImpl(UsersDao usersDao){
this.usersDaoMybaits = usersDao;
}
public UsersServiceImpl(){
System.out.println("Init.......");
}
@Override
public void addUsers() {
usersDaoMybaits.insertUsers();
// System.out.println("UsersService addUsers ......");
}
}
异常解除
依赖注入的数据类型
注入 Bean 对象
上面的示例也有讲解使用
方式一:
<property name="FieldName">
<ref bean="BeanID"/>
</property>
方式二:
<property name="FieldName" ref ="BeanID"/>
注入基本数据类型和字符串的值
方式一:
<property name="FieldName">
<value>content</value>
</property>
方式二:
<property name="FieldName" value="Content" />
示例:
<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="usersDao" class="com.bjsxt.dao.impl.UsersDaoImpl"/>
<!-- 新建一个Mybatis的bean对象 -->
<!--<bean id="usersDaoMybaits" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>-->
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl">
<property name="usersDao" ref="usersDao"/>
<property name="username">
<value>OldLiu</value>
</property>
<!-- 两种property格式,都可以 -->
<property name="userage" value="13"/>
</bean>
注意,之前的全局配置自动注入的配置需要删掉对应的属性和值
private String username;
private int userage;
public void setUsername(String username) {
this.username = username;
}
public void setUserage(int userage) {
this.userage = userage;
}
@Override
public void addUsers() {
usersDao.insertUsers();
System.out.println(this.userage+" "+this.username);
// System.out.println("UsersService addUsers ......");
}
注入List类型的数据
配置文件:
<property name="list">
<list>
<value>一个好名</value>
<value>itbz</value>
</list>
</property>
UsersServiceImpl类
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
@Override
public void addUsers() {
usersDao.insertUsers();
System.out.println(this.list);
// System.out.println("UsersService addUsers ......");
}
也可以使用 list.forEach(System.out::println);jianglist对象循环输出。
我们修改泛型,自建一个users实体类
package com.bjsxt.pojo;
public class Users {
private String username;
private int userage;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getUserage() {
return userage;
}
public void setUserage(int userage) {
this.userage = userage;
}
@Override
public String toString() {
return "Users{" +
"username='" + username + '\'' +
", userage=" + userage +
'}';
}
}
在UsersServiceImpl类内新建list
private List<Users> users;
public void setUsers(List<Users> users) {
this.users = users;
}
public void addUsers() {
usersDao.insertUsers();
users.forEach(System.out::println);
}
调用测试类,输出结果为:
注入 Set类型的数据
在UsersServiceImpl类内新建
private Set<Users> usersSet;
public void setUsersSet(Set<Users> usersSet) {
this.usersSet = usersSet;
}
public void addUsers() {
usersDao.insertUsers();
usersSet.forEach(System.out::println);
}
配置文件
<property name="usersSet">
<set>
<bean class="com.bjsxt.pojo.Users">
<property name="username" value="Oldlu-set"/>
<property name="userage" value="30"/>
</bean>
<bean class="com.bjsxt.pojo.Users">
<property name="username" value="admin-set"/>
<property name="userage" value="20"/>
</bean>
</set>
</property>
注入 Map类型的数据
- 第一种方式
配置文件
<property name="map">
<map>
<entry key="key1" value="value1"/>
<entry key="key2" value="value2"/>
</map>
</property>
在UsersServiceImpl类内
private Map<String,String> map;
public void setMap(Map<String, String> map) {
this.map = map;
}
public void addUsers() {
usersDao.insertUsers();
for(Map.Entry<String,String> entry:this.map.entrySet()){
System.out.println(entry.getKey()+"\t"+entry.getValue());
}
}
- 第二种方式
private Map<String,Users> usersMap;
public void setUsersMap(Map<String, Users> usersMap) {
this.usersMap = usersMap;
}
public void addUsers() {
usersDao.insertUsers();
for(Map.Entry<String,Users> entry:this.usersMap.entrySet()){
System.out.println(entry.getKey()+"\t"+entry.getValue());
}
}
<bean id="usersService" name="name1,name2" class="com.bjsxt.service.impl.UsersServiceImpl">
........
<property name="usersMap">
<map>
<entry key="users1" value-ref="users1" />
<entry key="users2" value-ref="users2" />
</map>
</property>
</bean>
<bean id="users1" class="com.bjsxt.pojo.Users">
<property name="username" value="Oldlu-map"/>
<property name="userage" value="30"/>
</bean>
<bean id="users2" class="com.bjsxt.pojo.Users">
<property name="username" value="admin-map"/>
<property name="userage" value="20"/>
</bean>
注入 Properties
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
public void addUsers() {
usersDao.insertUsers();
String value1 = this.properties.getProperty("pro1");
String value2 = this.properties.getProperty("pro2");
System.out.println(value1+"\t"+value2);
}
<property name="properties">
<props>
<prop key="pro1">provalue1</prop>
<prop key="pro2">provalue2</prop>
</props>
</property>