Spring
一.Spring概述
1.什么是Spring
Spring是分层的JavaEE应用 full-stack(全栈) 轻量级开源框架。 Spring的核心是IOC(Inverse Of Control:控制反转)和 AOP(Aspect Oriented Programming:面向切面编程) Spring一个全栈应用框架, 提供了表现层 Spring MVC 和持久层 Spring JDBC 以及业务层事务管理等众多应用技术 Spring还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架 ==Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技术。
2.为什么要学习Spring
- 最大程度的简化了开发
Spring是一个非常优秀的java框架,其目标是为了简化java企业级开发,Spring出来已经二十几年了,这期间也一直围绕着这个目标在进行,像后面需要学习的Springmvc、Springboot、Springcloud,这些技术也都是围绕着简化开发的目标在努力,到目前为止已经做的足够好了,可以说Spring除不能帮助我们实现业务逻辑代码之外,其他的事情Spring都尽量去帮我们简化,使用Spring可以帮助我们节约大量开发时间。 不使用Spring的情况下,开发一个项目可能需要2个月,用了Spring可能1个月都不需要,你说这样的技术你想学么?
- 大量公司使用
目前99%的公司使用了Spring,可以去各大招聘网站看一下,Spring算是必备技能,所以一定要掌握。
- 顶尖的源代码
Spring框架源码设计非常优秀,在java开源项目中可以说是顶级的,目前为止还未发现比Spring更优秀的开源项目,所以想提升代码能力的,强烈建议多看看Spring的源码;关于提升代码能力的,还可以去看一下jdk的源码,也是非常棒的,里面有很多大师的杰作。
3.Spring的发展历程
要谈Spring的历史,就要先谈J2EE。J2EE应用程序的广泛实现是在1999年和2000年开始的,它的出现带来了诸如事务管理之类的核心中间层概念的标准化,但是在实践中并没有获得绝对的成功,因为开发效率,开发难度和实际的性能都令人失望。 曾经使用过EJB开发JAVAEE应用的人,一定知道,在EJB开始的学习和应用非常的艰苦,很多东西都不能一下子就很容易的理解。EJB要严格地实现各种不同类型的接口,类似的或者重复的代码大量存在。而配置也是复杂和单调,同样使用JNDI进行对象查找的代码也是单调而枯燥。虽然有一些开发工作随着xdoclet的出现,而有所缓解,但是学习EJB的高昂代价,和极低的开发效率,极高的资源消耗,都造成了EJB的使用困难。而Spring出现的初衷就是为了解决类似的这些问题。 Spring的形成,最初来自Rod Jahnson所著的一本很有影响力的书籍《Expert One-on-One J2EE Design and Development》,就是在这本书中第一次出现了Spring的一些核心思想,该书出版于2002年。2004年编著《Expert one-on-one J2EE Development without EJB》阐述了JavaEE开发时不使用EJB的解决方式(Spring 雏形),同年4月spring1.0诞生。
2006年10月,发布 Spring2.0
2009年12月,发布 Spring3.0
2013年12月,发布 Spring4.0
2017年9月, 发布最新 Spring5.0 通用版(GA)
4.Spring的特点及优点
Spring 除了不能帮我们写业务逻辑.其余的几乎什么什么都能帮助我们简化开发
- 方便解耦,简化开发
通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
- AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。
- 声明式事务的支持
在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
- 方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。
- 方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支持。
- 降低Java EE API的使用难度
Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。
- Java 源码是经典学习范例
Spring的源码设计精妙、结构清晰、匠心独运,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。Spring框架源码无疑是Java技术的最佳实践范例。如果想在短时间内迅速提高自己的Java技术水平和应用开发水平,学习和研究Spring源码将会使你收到意想不到的效果。
一句话概括:Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)
5.Spring体系结构
二.IoC快速入门
提起Spring IoC,我们的第一反映都是控制反转,依赖注入。究其历史,如何理解这两句话的意思呢?
对于Spring IoC而言,支持的功能包含IOC Service Provider,对象创建管理和依赖注入服务。还有对象的生命周期管理,线程管理,查找服务等。
**IoC(Inverse of Control:控制反转)**是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。 IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。
IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 作者:是个程序员呀 https://www.bilibili.com/read/cv5553485/ 出处:bilibili
1.Ioc引入
- dao层
public interface UserDao { public void login(); }
public class UserDaoImpl implements UserDao { @Override public void login() { System.out.println("dao层登录成功!!!"); } }
- service层
public interface UserService { public void login(); }
public class UserServiceImpl implements UserService { //注入业务层 private UserDao userDao = new UserDaoImpl(); @Override public void login() { System.out.println("业务层 登录!!!"); //调用dao层方法 this.userDao.login(); } }
- 测试
public class UserServiceTest { //测试 @Test public void login() { UserService userService = new UserServiceImpl(); userService.login(); } }
2.反思
【思考分析】 代码过于耦合,上层代码过度依赖于下一层代码的实现: UserDAO userDAO = new UserDAOImpl(); 如果要更换实现类,必须要修改原来的业务代码!
解决方案:采用IoC(Inverse of Control,控制反转)的思想。 简单的说就是引入工厂(第三者),将原来在程序中手动创建管理的依赖的UserDAO对象,交给工厂来创建管理。在Spring框架中,这个工厂就是Spring中的工厂,因此,也可以说,将创建管理UserDAO对象的控制权被反转给了Spring框架了。
3.IoC的本质
控制反转IoC(Inversion of Control),是一种设计思想,而不是一种新的技术。DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法(不对)。没有IoC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方。 所谓控制反转就是:获得依赖对象的方式反转 IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解, 新版本的Spring也可以零配置实现IoC。 Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用 时再从Ioc容器中取出需要的对象
IoC (Inversion of Control),即控制反转。这不是一种新的技术,而是 Spring 的一种设计思想。
在传统的程序设计,我们直接在对象内部通过 new 来创建对象,是程序主动去创建依赖对象;而在 Spring 中有专门的一个容器来创建和管理这些对象,并将对象依赖的其他对象注入到该对象中,这个容器我们一般称为 IoC 容器。
所有的类的创建、销毁都由 Spring 来控制,也就是说控制对象生存周期的不再是引用它的对象,而是 Spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被 Spring 控制,所以这叫控制反转。
DI(Dependency Injection),即依赖注入,由 Martin Fowler 提出。可以认为 IoC 和 DI 其实是同一个概念的不同角度描述。
依赖注入是指组件之间的依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。
通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
2、bean
官方概念:在 Spring 中,构成应用程序主干并由 Spring IoC 容器管理的对象称为 bean。 bean 是一个由 Spring IoC 容器实例化,组装和管理的对象。
大白话:bean 可以认为是那些我们想注入到 Spring IoC 容器的 Java 对象实例的抽象。
我们经常会在 Service 上使用 @Service 注解,然后在要使用该 Service 的类中通过 @Autowire 注解来注入,这个 Service 就是一个 bean。在这个地方,@Service 注解相当于告诉 IoC 容器:这个类你需要帮我创建和管理;而 @Autowire 注解相当于告诉 IoC 容器:我需要依赖这个类,你需要帮我注入进来。
3、BeanDefinition
理解了 bean,BeanDefinition 就好理解了。BeanDefinition 是 bean 的定义,用来存储 bean 的所有属性方法定义。
4、BeanFactory 和 ApplicationContext
BeanFactory:基础类型 IoC 容器,提供完整的 IoC 服务支持。
ApplicationContext:BeanFactory 的子接口,在 BeanFactory 的基础上构建,是相对比较高级的 IoC 容器实现。包含 BeanFactory 的所有功能,还提供了其他高级的特性,比如:事件发布、国际化信息支持、统一资源加载策略等。正常情况下,我们都是使用的 ApplicationContext。
以电话来举例:
我们家里使用的 “座机” 就类似于 BeanFactory,可以进行电话通讯,满足了最基本的需求。
而现在非常普及的智能手机,iPhone、小米等,就类似于 ApplicationContext,除了能进行电话通讯,还有其他很多功能:拍照、地图导航、听歌等。
5、FactoryBean
一般情况下,我们将 bean 的创建和管理都交给 Spring IoC 容器,Spring 会利用 bean 的 class 属性指定的类来实例化 bean。
但是如果我们想自己实现 bean 的创建操作,可以实现吗?答案是可以的,FactoryBean 就可以实现这个需求。
FactoryBean 是一种特殊的 bean,它是个工厂 bean,可以自己创建 bean 实例,如果一个类实现了 FactoryBean 接口,则该类可以自己定义创建实例对象的方法,只需要实现它的 getObject() 方法即可。
FactoryBean 可能对于普通开发来说基本用不到也没去注意过,但是它其实应用的非常广,特别是在中间件中,如果你看过一些中间件的源码,一定会看到 FactoryBean 的身影。
4.IOC实现
4.1添加spring相关依赖
<!--spring相关--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.2.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.2.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.2.9.RELEASE</version> </dependency> <!--日志相关--> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
4.2核心配置文件
- 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"> <!-- 这就是spring的核心工厂 如何让工厂创建一个对象呢? bean: 表示是一个对象/类; 相当于 new UserDaoImpl(); id/name: 二选一,表示对象名,也是对外提供的唯一标识 class: 表示你交给工厂的哪个类(全路径) --> <bean id="userDao" class="cn.yanqi.dao.impl.UserDaoImpl"/> </beans>
4.3获取Bean对象
/** * @Auther: yanqi * @Desc 业务层 */ public class UserServiceImpl implements UserService { //注入业务层 // private UserDao userDao = new UserDaoImpl(); @Override public void login() { System.out.println("业务层登录!!!"); //现在要通过spring工厂来获取bean对象,如何获取呢? //1、找到bean对象所在的applicationContext.xml配置文件 //ClassPathXmlApplicationContext 会默认加载resources下的applicationContext.xml ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //2、找到工厂中bean的唯一标识 //方式一 UserDao userDao1 = (UserDao) applicationContext.getBean("userDao"); //方式二 UserDao userDao2 = applicationContext.getBean("userDao", UserDao.class); //方式三 通过找到接口类实现对象的创建,省去了bean的id或name --了解 UserDao userDao3 = applicationContext.getBean(UserDao.class); UserDao userDao4 = applicationContext.getBean(UserDaoImpl.class); //调用dao层方法 userDao3.login(); } }
三.DI依赖注入
DI Dependency Injection 依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件 简单的说,可以将一个bean对象动态的注入到另外一个bean中
5.1配置文件
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"> <!--创建dao对象--> <bean id="userDao" class="cn.yanqi.dao.impl.UserDaoImpl"/> <!--创建service对象--> <bean id="userService" class="cn.yanqi.service.impl.UserServiceImpl"> <!-- 在service层注入dao对象 property: 属性注入对象 name: 找到service层中提供的setXX方法,把set去掉,并把首字母小写 ref: 你要注入的哪bean对象,bean的id/name --> <property name="userDao" ref="userDao"/> </bean> </beans>
5.2属性对象注入
- service层
/** * @Auther: yanqi * @Desc 业务层 */ public class UserServiceImpl implements UserService { //属性注入 private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void login() { System.out.println("业务层 登录!!!"); //调用dao层方法 userDao.login(); } }
5.3测试
/** * @Auther: yanqi * @Desc 测试类 */ public class UserServiceTest { @Test public void login() { // UserService userService = new UserServiceImpl(); ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取bean对象 UserService userService = applicationContext.getBean("userService", UserService.class); userService.login(); } }
6.Spring核心接口
BeanFactory
这是IOC容器的顶级接口 它定义了IOC的最基础的功能, 但是其功能比较简单,一般面向Spring自身使用
在第一次使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化[用的时候再创建] --> 【懒汉设计】
ApplicationContext
这是在BeanFactory基础上衍生出的接口,它扩展了BeanFactory的功能,一般面向程序员使用
在容器启动时,一次性创建并加载了所有的Bean [初始化的时候全创建好] --> 【饿汉设计】
上面两种方式创建的对象都是单例, 只是创建对象的时机不同
public class UserServiceTest { @Test public void login() { // UserService userService = new UserServiceImpl(); // ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //BeanFactory是bean工厂的顶级接口,了解即可 BeanFactory beanFactory = new XmlBeanFactory(newClassPathResource("applicationContext.xml")); //获取bean对象 UserService userService = beanFactory.getBean("userService", UserService.class); userService.login(); } }
四.基于XML配置方式
实例化Bean的四种方式
第一种 无参数构造器 (最常用*)
public class Bean1 { }
<!--第一种: 无参构造--> <bean id="bean1" class="cn.yanqi.bean.Bean1"/>
@Test public void login() { //获取配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取bean对象 Bean1 bean1 = applicationContext.getBean("bean1", Bean1.class); System.out.println(bean1); }
第二种 静态方式
public class Product { private Integer id; private String name; }
public class StaticFactory { static Product getInstance(){ return new Product(); } }
<!--相当于这里创建一bean2Test对象,直接调用了initBean2静态方法--> <bean id="staticFactory" class="com.yh.pojo.StaticFactory" factory-method="getInstance"/>
@Test public void login() { //获取配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取bean对象 Bean2 bean2 = applicationContext.getBean("bean2", Bean2.class); System.out.println(bean2); }
第三种 普通方法
public class Product { private Integer id; private String name; }
public class ProFactory { public Product getProduct(){ return new Product(); } }
<!--第三种: 普通方法--> <bean id="proFactory" class="com.yh.pojo.ProFactory"/> <bean id="product" factory-method="getProduct" factory-bean="proFactory"/>
@Test public void login() { //获取配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Product product = (Product) ac.getBean("product"); System.out.println(product); }
第四种 FactoryBean方式-了解
public class Bean4 { }
/** * @Desc 实现FactoryBean接口 */ public class Bean4Test implements FactoryBean<Bean4> { //返回bean对象即可 @Override public Bean4 getObject() throws Exception { return new Bean4(); } @Override public Class<?> getObjectType() { return null; } }
<!--第四种: FactoryBean方式--> <bean id="bean4" class="cn.yanqi.bean.Bean4Test"/>
@Test public void login() { //获取配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取bean对象 Bean4 bean4 = applicationContext.getBean("bean4", Bean4.class); System.out.println(bean4); }
五.Bean对象配置
相关属性
属性名 | 描述 |
id | 在ioc容器的唯一标识 |
class | 创建对象实例的全限定名 |
scope | 声明此对象的作用范围 singleton:单例对象(默认) prototype:多例对象 |
init-method | 在对象创建时,执行此方法 |
destroy-method | 在对象销毁时,执行此方法 |
Bean的作用域
Singleton: 在一个spring容器中,对象只有一个实例。(默认值)
Prototype: 在一个spring容器中,存在多个实例,每次getBean 返回一个新的实例
public class SingletonBean { public SingletonBean() { System.out.println("我是单例。。。"); } }
public class PrototypeBean { public PrototypeBean() { System.out.println("我是多例。。。。"); } }
<!--spring默认是单例--> <!--单例--> <bean id="singletonBean" class="cn.yanqi.scope.SingletonBean" scope="singleton"/> <!--多例--> <bean id="prototypeBean" class="cn.yanqi.scope.PrototypeBean" scope="prototype"/>
测试
@Test public void login() { //获取配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //作用域 SingletonBean singletonBean1 = applicationContext.getBean("singletonBean", SingletonBean.class); SingletonBean singletonBean2 = applicationContext.getBean("singletonBean", SingletonBean.class); System.out.println(singletonBean1); System.out.println(singletonBean2); PrototypeBean prototypeBean1 = applicationContext.getBean("prototypeBean", PrototypeBean.class); PrototypeBean prototypeBean2 = applicationContext.getBean("prototypeBean", PrototypeBean.class); System.out.println(prototypeBean1); System.out.println(prototypeBean2); }
Bean的生命周期
生命周期主要演示对象的创建和销毁时机!!!
需要用到两个属性: init-method 和 destroy-method
lifecycle
public class LifecycleDemo { public LifecycleDemo() { System.out.println("对象实例化了"); } public LifecycleDemo(String name) { //带一个参数的构造方法 } public void initBean(){ System.out.println("bean初始化"); } public void DistroyBean(){ System.out.println("bean销毁"); } }
<!--bean对象的生命周期--> <bean id="lifecycleDemo" class="cn.yanqi.lifecycle.LifecycleDemo" init-method="initBean" destroy-method="distroyBean"/>
@Test public void login() { //获取配置文件 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); LifecycleDemo lifecycleDemo = applicationContext.getBean("lifecycleDemo", LifecycleDemo.class); System.out.println(lifecycleDemo); }
查看结果:
对象实例化了
初始化
我是单例。。。
cn.yanqi.lifecycle.LifecycleDemo@7b69c6ba
测试查看控制台打印,发现销毁方法没有执行。 原因:销毁方法的执行必须满足两个条件: 1) 单例(singleton)的bean才可以手动销毁。 2) 必须手动关闭容器(close)时,才会执行手动销毁的方法。 多例没就destroy-method 方法,只对单例有作用
- 手动关闭
@Test public void login() { //获取配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); LifecycleDemo lifecycleDemo = applicationContext.getBean("lifecycleDemo", LifecycleDemo.class); System.out.println(lifecycleDemo); //使用junit调用时,当调用完毕时,junit会强制关jvm,但些时spring容器还没来的及关闭,所以不会有销毁方法 //想要看到销毁方法,需要手动关闭 ((ClassPathXmlApplicationContext)applicationContext).close(); }
六.Bean属性的依赖注入
什么是Bean属性的注入?就是对 一个对象的属性赋值
constructor
1.构造方法注入
有参注入和无参注入
public class Car { private Integer id; private String name; private Double price; //提供有参无参构造方法,set get方法 toString方法 //可以写索引序号 }
<bean id="car" class="cn.yanqi.constructor.Car"> <constructor-arg name="id" value="1009"/> <constructor-arg name="name" value="滑板车"/> <constructor-arg name="price" value="99"/> </bean>
@Test public void login() { //获取配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //传统写法 Car car = new Car(1008,"单车",2d); System.out.println(car); //构造器属性注入 Car car2 = applicationContext.getBean("car", Car.class); System.out.println(car2); }
2.set方法注入
<bean id="car" class="cn.yanqi.constructor.Car"> <!--必须给set方法,name找的是对应的set方法--> <property name="id" value="1009"/> <property name="name" value="共享单车"/> <property name="price"> <value>1.5</value> </property> </bean>
我再创建一个person对象
public class Person { private Integer id; private String name; private Car car; //提供有参无参构造方法,set get方法 toString方法 }
<bean id="car" class="cn.yanqi.constructor.Car"> <!--必须给set方法,name找的是对应的set方法--> <property name="id" value="1009"/> <property name="name" value="共享单车"/> <property name="price" value="1.5"/> </bean> <bean id="person" class="cn.yanqi.constructor.Person"> <property name="id" value="88"/> <property name="name" value="jack"/> <!--这里是引的car的bean对象--> <property name="car" ref="car"/> </bean>
@Test public void login() { //获取配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //set属性注入 Person person = applicationContext.getBean("person", Person.class); System.out.println(person); }
结果: Person{id=88, name=‘java’, car=Car{id=1009, name=‘共享单车’, price=1.5}}
3.P命名空间注入
p名称空间出现的目地为了简化以上两种注入方式
引入p名称空间约束头
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" 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">
<!--p名称空间属性注入--> <bean id="person2" class="cn.yanqi.constructor.Person" p:id="99" p:name="rose" p:car-ref="car" />
@Test public void login() { //获取配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //set属性注入 Person person = applicationContext.getBean("person2", Person.class); System.out.println(person); }
查看结果: Person{id=99, name=‘rose’, car=Car{id=1009, name=‘共享单车’, price=1.5}}
4.集合类型属性注入
@Data public class ConllectionBean { private List<String> list; private Set<Integer> set; private Map<Integer,String> map; private Properties properties; }
<bean id="conllectionBean" class="cn.yanqi.constructor.ConllectionBean"> <!--list--> <property name="list"> <list> <value>aaa</value> <value>bbb</value> <value>ccc</value> </list> </property> <!--set--> <property name="set"> <set> <value>11</value> <value>22</value> <value>33</value> </set> </property> <!--map--> <property name="map"> <map> <entry key="11" value="aa"/> <entry key="22" value="bb"/> <entry key="33" value="cc"/> </map> </property> <!--properties--> <property name="properties"> <props> <prop key="a">aa</prop> <prop key="b">bb</prop> <prop key="c">cc</prop> </props> </property> </bean>
@Test public void login() { //获取配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //set属性注入 ConllectionBean conllectionBean = applicationContext.getBean("conllectionBean", ConllectionBean.class); System.out.println(conllectionBean); }
七.基于注解配置方式
spring-ioc-annotation
bean对象-注解
Spring 的【XML开发】和【注解开发】 导入依赖包是相同的
public interface UserDao { public void login(); }
@Component("userDao")// 相当于 <bean id="userDao" class="cn.yanqi.dao.impl.UserDaoImpl"/> public class UserDaoImpl implements UserDao { @Override public void login() { System.out.println("dao层登录成功!!!"); } }
public interface UserService { public void login(); }
/** @Component("userService") 相当于<bean id="userService" class="cn.yanqi.service.impl.UserServiceImpl"/> @Autowired 相当于 <bean id="userService" class="cn.yanqi.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean> */ @Component("userService") public class UserServiceImpl implements UserService { //注入dao层对象 @Autowired private UserDao userDao; @Override public void login() { System.out.println("业务层 登录!!!"); userDao.login(); } }
applicationContext.xml
注意,这里用注释方式,约束引入context 名称空间
<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:annotation-config/> <!-- 扫描注解包 ,扫描包下含有@Component的类,就是bean对象 <context:component-scan> 包含了 <context:annotation-config/>功能 --> <context:component-scan base-package="cn.yanqi"/> </beans>
Component-注解
@Component()是父注解 三个子注解具有分层含义 @Controller @Service @Repository
@Repository("userDao") public class UserDaoImpl implements UserDao { @Override public void login() { System.out.println("dao层登录成功!!!"); } }
@Service("userService") public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public void login() { System.out.println("业务层 登录!!!"); userDao.login();}}
@Test public void login() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = applicationContext.getBean("userService", UserService.class); userService.login(); }
Bean属性的依赖注入
- 简单数据类型依赖注入
@Value(“22”)
@Data @Component public class Car { @Value("22") private Integer id; @Value("单车") private String name; @Value("1.5") private Double price; }
@Test public void login() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Car car = applicationContext.getBean("car", Car.class); System.out.println(car); }
查看结果: Car(id=22, name=单车, price=1.5)
- 复杂类型数据依赖注入
@Autowired
@Resource
@Service("userService") public class UserServiceImpl implements UserService { //第一种注入方式 @Autowired //第二种注入方式 // @Resource private UserDao userDao; @Override public void login() { System.out.println("业务层 登录!!!"); userDao.login(); } }
@Test public void login() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = applicationContext.getBean("userService", UserService.class); userService.login(); }
Bean的初始化方法和销毁方法
@PostConstruct //初始化 == init-method
@PreDestroy //销毁 == destory-method
@Component public class liftBean { @PostConstruct //初始化 == init-method public void aa(){ System.out.println("我初始化了"); } @PreDestroy //销毁 == destory-method public void bb(){ System.out.println("我over了"); } }
@Test public void login() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); applicationContext.getBean("liftBean", liftBean.class); //手动关闭,才会销毁 ((ClassPathXmlApplicationContext)applicationContext).close(); }
Bean的作用域
@Scope(“singleton”)//单例
@Scope(“prototype”)//多例
@Component @Scope("singleton")//单例 @Scope("prototype")//多例 public class LiftBean { @PostConstruct //初始化 == init-method public void aa(){ System.out.println("我初始化了"); } @PreDestroy //销毁 == destory-method public void bb(){ System.out.println("我over了"); } }
@Test public void login() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); liftBean liftBean = applicationContext.getBean("liftBean", liftBean.class); liftBean liftBean2 = applicationContext.getBean("liftBean", liftBean.class); System.out.println(liftBean); System.out.println(liftBean2); }
XML和注解混合配置 (重点)
public class UserDaoImpl implements UserDao { @Override public void login() { System.out.println("dao层登录成功!!!"); } }
public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public void login() { System.out.println("业务层 登录!!!"); userDao.login(); } }
<!--dao对象--> <bean id="userDao" class="cn.yanqi.dao.impl.UserDaoImpl"/> <!--service对象--> <bean id="userService" class="cn.yanqi.service.impl.UserServiceImpl"/> <!--开启注释 扫描 @PostConstruct @PreDestroy @Autowired @Resource --> <context:annotation-config/>
@Test public void login() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = applicationContext.getBean("userService", UserService.class); userService.login(); }
提示:因为采用注解开发时, <context:component-scan> 具有<context:annotation-config>的功能 。如果没有配置注解扫描,需要单独配置 <context:annotation-config>, 才能使用注解注入!
Xml配置文件名字问题
spring的核心配置文件名,是可以随便书写的,只要在加载时能加载到配置文件即可
11.Spring的junit测试集成
代码实现
Spring提供 spring-test.jar 可以整合junit。
好处:可以简化测试代码(不需要手动创建上下文)
<!--单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--spring-test--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.9.RELEASE</version> </dependency>
spring整合junit代码实现
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class UserServiceTest { //注入业务层 @Autowired private UserService userService; @Test public void login() { /*ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = applicationContext.getBean("userService", UserService.class);*/ userService.login(); } }
@Service //直接注入不用再写对象名了 public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public void login() { System.out.println("业务层 登录!!!"); userDao.login(); } }
@Repository //直接注入不用再写对象名了 public class UserDaoImpl implements UserDao { @Override public void login() { System.out.println("dao层登录成功!!!"); } }
ringframework
spring-test
5.2.9.RELEASE
spring整合junit代码实现 ```java @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class UserServiceTest { //注入业务层 @Autowired private UserService userService; @Test public void login() { /*ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = applicationContext.getBean("userService", UserService.class);*/ userService.login(); } }
@Service //直接注入不用再写对象名了 public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public void login() { System.out.println("业务层 登录!!!"); userDao.login(); } }
@Repository //直接注入不用再写对象名了 public class UserDaoImpl implements UserDao { @Override public void login() { System.out.println("dao层登录成功!!!"); } }