Spring是一个开源免费的框架,为了解决企业应用开发的复杂性而创建。Spring框架是一个轻量级的解决方案,可以一站式地构建企业级应用。Spring是模块化的,所以可以只使用其中需要的部分。可以在任何web框架上使用控制反转(IoC),也可以只使用Hibernate集成代码或JDBC抽象层。它支持声明式事务管理、通过RMI或web服务实现远程访问,并可以使用多种方式持久化数据。它提供了功能全面的MVC框架,可以透明地集成AOP到软件中。
Spring被设计为非侵入式的,这意味着你的域逻辑代码通常不会依赖于框架本身。在集成层(比如数据访问层),会存在一些依赖同时依赖于数据访问技术和Spring,但是这些依赖可以很容易地从代码库中分离出来。
Spring框架是基于Java平台的,它为开发Java应用提供了全方位的基础设施支持,并且它很好地处理了这些基础设施,所以你只需要关注你的应用本身即可。
Spring可以使用POJO(普通的Java对象,plain old java objects)创建应用,并且可以将企业服务非侵入式地应用到POJO。这项功能适用于Java SE编程模型以及全部或部分的Java EE。
那么,做为开发者可以从Spring获得哪些好处呢?
不用关心事务API就可以执行数据库事务;
不用关心远程API就可以使用远程操作;
不用关心JMX API就可以进行管理操作;
不用关心JMS API就可以进行消息处理。
①JMX,Java Management eXtension,Java管理扩展,是一个为应用程序、设备、系统等植入管理功能的框架。JMX可以跨越一系列异构操作系统平台、系统体系结构和网络传输协议,灵活的开发无缝集成的系统、网络和服务管理应用。
②JMS,Java Message Service,Java消息服务,是Java平台上有关面向消息中间件(MOM)的技术规范,它便于消息系统中的Java应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发。
一句话概括:Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。
私信博主777免费获取
2002年,Rod Jahnson在《Expert One-on-One J2EE Design and Development》书中首次推出了Spring框架雏形interface21框架。
2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。
从2004年3月到现在,已经经历了1.0、1.1、1.2、2.0、2.5、3.0、3.1几个主要的版本
轻量:从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。
控制反转Ioc:Spring通过一种称作控制反转(IoC)的技术促进了低耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。
面向切面Aop:Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
容器:Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
框架:Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
MVC:Spring的作用是整合,但不仅仅限于整合,Spring 框架可以被看做是一个企业解决方案级别的框架,Spring MVC是一个非常受欢迎的轻量级Web框架。
所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
Spring 框架的功能可以用在任何 J2EE 服务器中,大多数功能也适用于不受管理的环境。Spring 的核心要点是:支持不绑定到特定 J2EE 服务的可重用业务和数据访问对象。毫无疑问,这样的对象可以在不同 J2EE 环境 (Web 或 EJB)、独立应用程序、测试环境之间重用。
Spring是一个开源的框架,现在的Spring框架构成了一个体系平台,通过Spring的官方网站
http://www.springsource.org可以了解到,围绕着Spring框架本身,还有许多其他优秀的项目:
SpringFramework(Core):核心项目
Spring Web Flow:工作流项目
Spring Security:安全项目
Spring Batch:批量数据处理项目
Spring Android:Android系统支持项目
Spring Social:社交项目
Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务,Spring Cloud是一个基于Spring Boot实现的云应用开发工具;Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置,Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。
SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中我们使用面向对象编程对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
假设项目中需要完成对图书的数据访问服务,我们定义好了IBookDAO接口与BookDAO实现类
创建maven项目:
IBookDAO接口如下:
package com.zhangguo.Spring051.ioc01;
/**
* 图书数据访问接口
*/
public interface IBookDAO {
/**
* 添加图书
*/
public String addBook(String bookname);
}
BookDAO实现类如下:
package com.zhangguo.Spring051.ioc01;
/**
* 图书数据访问实现类
*/
public class BookDAO implements IBookDAO {
public String addBook(String bookname) {
return "添加图书"+bookname+"成功!";
}
}
Maven项目的pom.xml如下:
4.0.0
com.zhangguo
Spring051
0.0.1-SNAPSHOT
jar
Spring051
http://maven.apache.org
UTF-8
4.3.0.RELEASE
junit
junit
test
4.10
org.springframework
spring-context
${spring.version}
org.aspectj
aspectjweaver
1.8.9
cglib
cglib
3.2.4
业务类BookService如下:
package com.zhangguo.Spring051.ioc01;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 图书业务类
*/
public class BookService {
IBookDAO bookDAO;
public BookService() {
//容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("IOCBeans01.xml");
//从容器中获得id为bookdao的bean
bookDAO=(IBookDAO)ctx.getBean("bookdao");
}
public void storeBook(String bookname){
System.out.println("图书上货");
String result=bookDAO.addBook(bookname);
System.out.println(result);
}
}
容器的配置文件IOCBeans01.xml如下:
测试类Test如下:
package com.zhangguo.Spring051.ioc01;
public class Test {
@org.junit.Test
public void testStoreBook()
{
BookService bookservice=new BookService();
bookservice.storeBook("《Spring MVC权威指南 第一版》");
}
}
运行结果:
如下所示,则上下文会使用无参构造方法创建对象
Person.java
package spring02;
/**人*/
public abstract class Person {
public String name;
}
Student.java
package spring02;
/**学生*/
public class Student extends Person {
/**身高*/
public int height;
/**有参构造方法*/
public Student(String name,int height){
this.name=name;
this.height=height;
}
@Override
public String toString() {
return "Student{" + "height=" + height+",name="+name +'}';
}
}
School.java
package spring02;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class School {
public static void main(String[] args) {
//IoC容器
ApplicationContext ctx=
new ClassPathXmlApplicationContext("bookbean01.xml","beans02.xml");
//从容器中获取对象
Person tom=ctx.getBean("tom",Person.class);
System.out.println(tom);
}
}
配置文件beans02.xml
运行结果:
注意:如果在使用构造方法时不想通过参数名称指定参数则可以直接使用索引,如:
Address地址类:
package spring02;
/**地址*/
public class Address {
/**国家*/
private String country;
/**城市*/
private String city;
public Address() {
}
public Address(String country, String city) {
this.country = country;
this.city = city;
}
@Override
public String toString() {
return "Address{" +
"country='" + country + '\'' +
", city='" + city + '\'' +
'}';
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
配置文件beans02.xml:
测试代码:
package spring02;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class School {
public static void main(String[] args) {
//IoC容器
ApplicationContext ctx=
new ClassPathXmlApplicationContext("bookbean01.xml","beans02.xml");
//从容器中获取对象
Person tom=ctx.getBean("rose",Person.class);
Address zhuhai=ctx.getBean("zhuhai",Address.class);
System.out.println(zhuhai);
}
}
运行结果:
便捷方式:
你可以使用id 或(和) name 属性来指定bean的标识符
Person
package spring02;
/**人*/
public abstract class Person {
/**姓名*/
public String name;
/**地址*/
public Address address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Student
package spring02;
/**学生*/
public class Student extends Person {
/**身高*/
public int height;
/**有参构造方法*/
public Student(String name,int height){
this.name=name;
this.height=height;
}
/**有参构造方法*/
public Student(String name,int height,Address address){
this.name=name;
this.height=height;
this.address=address;
}
@Override
public String toString() {
return "Student{" + "height=" + height+",name="+name +'}'+address;
}
}
配置文件
测试代码:
package spring02;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class School {
public static void main(String[] args) {
//IoC容器
ApplicationContext ctx=
new ClassPathXmlApplicationContext("bookbean01.xml","beans02.xml");
//从容器中获取对象
Person tom=ctx.getBean("tom",Person.class);
Person rose=ctx.getBean("rose",Person.class);
//Address zhuhai=ctx.getBean("zhuhai",Address.class);
System.out.println(tom);
System.out.println(rose);
}
}
运行结果:
从容器中取回的对象默认是单例的:
Person roseA=ctx.getBean("rose",Person.class);
Person roseB=ctx.getBean("rose",Person.class);
//Address zhuhai=ctx.getBean("zhuhai",Address.class);
System.out.println(tom);
System.out.println(roseA==roseB);
运行结果:
使用scope属性可以指定作用域
测试代码:
//从容器中获取对象
Person tom=ctx.getBean("tom",Person.class);
Person roseA=ctx.getBean("rose",Person.class);
Person roseB=ctx.getBean("rose",Person.class);
//Address zhuhai=ctx.getBean("zhuhai",Address.class);
System.out.println(tom);
System.out.println(roseA==roseB);
运行结果:
ApplicationContext实现的默认行为就是再启动时将所有 singleton bean提前进行实例化。 通常这样的提前实例化方式是好事,因为配置中或者运行环境的错误就会被立刻发现,否则可能要花几个小时甚至几天。如果你不想 这样,你可以将单例bean定义为延迟加载防止它提前实例化。延迟初始化bean会告诉Ioc容器在第一次需要的时候才实例化而不是在容器启动时就实例化。
在XML配置文件中,延迟初始化通过
XML:
用例:
@Test
public void testMethod3() throws Exception {
//通过spring配置文件初始化一个容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("springCfg.xml");
Thread.sleep(2000);
Person mark1=ctx.getBean("mark",Person.class);
Thread.sleep(2000);
Person mark2=ctx.getBean("mark",Person.class);
System.out.println(mark1==mark2);
}
结果:
配置文件:
Student类:
package spring02;
import java.io.File;
/**学生*/
public class Student extends Person {
/**身高*/
public int height;
/**有参构造方法*/
public Student(String name,int height){
this.name=name;
this.height=height;
}
/**有参构造方法*/
public Student(String name,int height,Address address){
this.name=name;
this.height=height;
this.address=address;
}
@Override
public String toString() {
return "Student{" + "height=" + height+",name="+name +'}'+address;
}
public void init(){
System.out.println("对象被创建");
}
public void over(){
System.out.println("对象被回收");
}
}
运行结果:
实现
org.springframework.beans.factory.DisposableBean 接口,允许一个bean当容器需要其销毁时获得一次回调。 DisposableBean 接口也只规定了一个方法:
void destroy() throws Exception;
建议不使用 DisposableBean 回调接口,因为会与Spring耦合。使用@PreDestroy 注解或者指定一个普通的方法,但能由bean定义支持。基于XML配置的元数据,使用
示例
public class ExampleBean {
public void cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
与下面效果相同:
示例:
public class AnotherExampleBean implements DisposableBean {
public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}
但是不与Spring耦合。
上一个示例是使用传统的xml配置完成IOC的,如果内容比较多则配置需花费很多时间,通过注解可以减轻工作量,但注解后修改要麻烦一些,偶合度会增加,应该根据需要选择合适的方法。
package com.zhangguo.Spring051.ioc02;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
/**
* 图书数据访问实现类
*/
@Component("bookdaoObj")
public class BookDAO implements IBookDAO {
public String addBook(String bookname) {
return "添加图书"+bookname+"成功!";
}
}
在类上增加了一个注解Component,在类的开头使用了@Component注解,它可以被Spring容器识别,启动Spring后,会自动把它转成容器管理的Bean。
除了@Component外,Spring提供了3个功能基本和@Component等效的注解,分别对应于用于对DAO,Service,和Controller进行注解。
1:@Repository 用于对DAO实现类进行注解。
2:@Service 用于对业务层注解,但是目前该功能与 @Component 相同。
3:@Constroller用于对控制层注解,但是目前该功能与 @Component 相同。
package com.zhangguo.Spring051.ioc02;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* 图书业务类
*/
@Component
public class BookService {
IBookDAO bookDAO;
public void storeBook(String bookname){
//容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("IOCBeans02.xml");
//从容器中获得id为bookdao的bean
bookDAO=(IBookDAO)ctx.getBean("bookdaoObj");
System.out.println("图书上货");
String result=bookDAO.addBook(bookname);
System.out.println(result);
}
}
将构造方法中的代码直接写在了storeBook方法中,避免循环加载的问题。
粗体字是新增的xml命名空间与模式约束文件位置。增加了注解扫描的范围,指定了一个包,可以通过属性设置更加精确的范围如:
resource-pattern:对指定的基包下面的子包进行选取
include-filter:指定需要包含的包
exclude-filter:指定需要排除的包
include-filter表示需要包含的目标类型,exclude-filter表示需要排除的目标类型,type表示采的过滤类型,共有如下5种类型:
Filter Type |
Examples Expression |
Description |
annotation |
org.example.SomeAnnotation |
注解了SomeAnnotation的类 |
assignable |
org.example.SomeClass |
所有扩展或者实现SomeClass的类 |
aspectj |
org.example..*Service+ |
AspectJ语法表示org.example包下所有包含Service的类及其子类 |
regex |
org\.example\.Default.* |
Regelar Expression,正则表达式 |
custom |
org.example.MyTypeFilter |
通过代码过滤,实现 |
expression表示过滤的表达式。
只扫描
com.zhangguo.Spring051.ioc04下所有名称以A开始的类。
测试类
package com.zhangguo.Spring051.ioc02;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
@org.junit.Test
public void testStoreBook()
{
//容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("IOCBeans02.xml");
BookService bookservice=ctx.getBean(BookService.class);
bookservice.storeBook("《Spring MVC权威指南 第二版》");
}
}
运行结果:
IBookDao接口
package spring11;
public interface IBookDao {
void add();
}
BookDao实现类
package spring11;
import org.springframework.stereotype.Component;
@Component("bookdao")
public class BookDao implements IBookDao {
public void add() {
System.out.println("新增图书成功!");
}
}
MSBookDao实现类
package spring11;
import org.springframework.stereotype.Component;
@Component("bookdao")
public class MSBookDao implements IBookDao {
public void add() {
System.out.println("新增图书到SQLServer成功!");
}
}
BookService测试类:
package spring11;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BookService {
public static void main(String[] args) {
//容器
ApplicationContext ctx=
new ClassPathXmlApplicationContext(new String[]{"bookbean11.xml"});
//从容器中获得对象
IBookDao dao=ctx.getBean("bookdao",IBookDao.class);
dao.add();
}
}
XML配置:
运行结果:
指定两个bookdao是不正确的,重名了,但是因为在组件扫描中我们排除了一个所有也可以正确运行。
默认容器中的bean是单例的:
//从容器中获得对象
IBookDao dao1=ctx.getBean("bookdao",IBookDao.class);
IBookDao dao2=ctx.getBean("bookdao",IBookDao.class);
System.out.println(dao1==dao2);
结果:
修改成原型
package spring11;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component("bookdao")
@Scope("prototype")
public class MSBookDao implements IBookDao {
public void add() {
System.out.println("新增图书到SQLServer成功!");
}
}
结果:
用来指定bean的作用域
singleton---单例 只创建一个对象。
prototype---原型 想创建多少个就创建多少了。
request---针对Web项目,不同的请求创建单独的Bean对象,同一个请求共享一个Bean。
session---针对Web项目,不同的会话创建单独的Bean对象,同一个会话共享一个Bean。
默认情况下Spring IoC容器在初始化时将Bean创建好存放到容器中:
测试:
@Test
public void testMethod6() throws Exception {
//通过spring配置文件初始化一个容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("springCfg2.xml");
Thread.sleep(6000);
IBookDao dao=ctx.getBean("mssql",IBookDao.class);
dao.add("<>");
}
结果:
此处等待6秒...
增加注解修改成延迟初始化bean
package dao;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
@Repository("mssql")
@Lazy
public class SQLServerBookDao implements IBookDao {
public SQLServerBookDao() {
System.out.println("SQLServerBookDao构造方法被调用");
}
/**
* 添加图书
*
* @param name
*/
public void add(String name) {
System.out.println("添加图书到SQLServer数据库成功:"+name);
}
}
再次测试结果:
然后
@PostConstruct 初始化方法的注解方式 等同与在XML中声明init-method=init
package dao;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
@Repository("mssql")
@Lazy
public class SQLServerBookDao implements IBookDao {
public SQLServerBookDao() {
System.out.println("SQLServerBookDao构造方法被调用");
}
/**
* 添加图书
*
* @param name
*/
public void add(String name) {
System.out.println("添加图书到SQLServer数据库成功:"+name);
}
//init-method callback
@PostConstruct
public void init(){
System.out.println("SQLServerBookDao初创建完成了");
}
}
结果
@PreDestroy 销毁方法的注解方式 等同于在XML中声明destory-method=destory
package dao;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Repository("mssql")
@Lazy
public class SQLServerBookDao implements IBookDao {
public SQLServerBookDao() {
System.out.println("SQLServerBookDao构造方法被调用");
}
/**
* 添加图书
*
* @param name
*/
public void add(String name) {
System.out.println("添加图书到SQLServer数据库成功:"+name);
}
//init-method callback
@PostConstruct
public void init(){
System.out.println("SQLServerBookDao初创建完成了");
}
//destory-method callback
@PreDestroy
public void destory(){
System.out.println("SQLServerBookDao准备销毁了");
}
}
如果使用Compont注解时不指定名称,基于@Componet及其扩展(如@Servic和自定义等)标注和classpath-scan定义的Bean,注解有一个value属性,如果提供了,那么就此Bean的名字。如果不提供。就会使用Spring默认的命名机制,即简单类名且第一个字母小写
package spring11;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component() //未指定名称
@Scope("prototype")
public class MSBookDao implements IBookDao {
public void add() {
System.out.println("新增图书到SQLServer成功!");
}
}
测试:
package spring11;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BookService {
public static void main(String[] args) {
//容器
ApplicationContext ctx=
new ClassPathXmlApplicationContext(new String[]{"bookbean11.xml"});
//从容器中获得对象
IBookDao dao1=ctx.getBean("MSBookDao",IBookDao.class);
IBookDao dao2=ctx.getBean("MSBookDao",IBookDao.class);
System.out.println(dao1==dao2);
dao1.add();
}
}
结果:
在基于XML的配置中bean标签还有很多属性,如scope、Lazy、init-method、depends-on、Qualifier等。
从容器中获取实例时也可以直接根据类型获取
package spring12;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class BookStore {
@Autowired
BookService service;
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bookbean12.xml");
BookStore store =ctx.getBean(BookStore.class);
store.service.addNewBook();
A a=ctx.getBean("a",A.class);
System.out.println(a);
}
}
@Component
class A{
}
@Component
class B extends A{
}
结果:
默认名称时需要将首字母小写,Camel命名规范:
package dao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
@Component
public class MySqlBookDao implements IBookDao {
/**
* 添加图书
*
* @param name
*/
public void add(String name) {
System.out.println("添加图书到MySQL数据库成功:"+name);
}
}
测试:
@Test
public void testMethod5() throws Exception {
//通过spring配置文件初始化一个容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("springCfg2.xml");
IBookDao bookDao=ctx.getBean("mySqlBookDao",IBookDao.class);
bookDao.add("《Spring从入门到精通》");
}
结果:
从配置文件中我们可以看出我们并没有声明bookdaoObj与BookService类型的对象,但还是从容器中获得了实例并成功运行了,原因是:在类的开头使用了@Component注解,它可以被Spring容器识别,启动Spring后,会自动把它转成容器管理的Bean。
从上一个示例中可以看出有两个位置都使用了ApplicationContext初始化容器后获得需要的Bean,可以通过自动装配简化。
package com.zhangguo.Spring051.ioc03;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
/**
* 图书数据访问实现类
*/
@Repository
public class BookDAO implements IBookDAO {
public String addBook(String bookname) {
return "添加图书"+bookname+"成功!";
}
}
把注解修改成了Repository,比Component更贴切一些,非必要。
package com.zhangguo.Spring051.ioc03;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;
/**
* 图书业务类
*/
@Service
public class BookService {
@Autowired
IBookDAO bookDAO;
public void storeBook(String bookname){
System.out.println("图书上货");
String result=bookDAO.addBook(bookname);
System.out.println(result);
}
}
将类BookService上的注解替换成了Service;在bookDao成员变量上增加了一个注解@Autowired,该注解的作用是:可以对成员变量、方法和构造函数进行注解,来完成自动装配的工作,通俗来说就是会根据类型从容器中自动查到到一个Bean给bookDAO字段。@Autowired是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Qualifier。另外可以使用其它注解,@ Resource :等同于@Qualifier,@Inject:等同于@ Autowired。
@Service用于注解业务层组件(我们通常定义的service层就用这个)
@Controller用于注解控制层组件(如struts中的action)
@Repository用于注解数据访问组件,即DAO组件
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行注解。
装配注解主要有:@Autowired、@Qualifier、@Resource,它们的特点是:
1、@Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入;
2、@Autowired默认是按照类型装配注入的,如果想按照名称来转配注入,则需要结合@Qualifier一起使用;
3、@Resource注解是又J2EE提供,而@Autowired是由spring提供,故减少系统对spring的依赖建议使用@Resource的方式;如果Maven项目是1.5的JRE则需换成更高版本的。
4、@Resource和@Autowired都可以书写注解在字段或者该字段的setter方法之上
5、@Autowired 可以对成员变量、方法以及构造函数进行注释,而 @Qualifier 的注解对象是成员变量、方法入参、构造函数入参。
6、@Qualifier("XXX") 中的 XX是 Bean 的名称,所以 @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。
7、@Autowired 注释进行自动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个,通过属性required可以设置非必要。
8、@Resource装配顺序
8.1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
8.2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
8.3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
8.4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
package com.zhangguo.Spring051.ioc05;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;
/**
* 图书业务类
*/
@Service
public class BookService {
public IBookDAO getDaoofbook() {
return daoofbook;
}
/*
@Autowired
@Qualifier("bookdao02")
public void setDaoofbook(IBookDAO daoofbook) {
this.daoofbook = daoofbook;
}*/
@Resource(name="bookdao02")
public void setDaoofbook(IBookDAO daoofbook) {
this.daoofbook = daoofbook;
}
/*
@Autowired
@Qualifier("bookdao02")
*/
IBookDAO daoofbook;
/*
public BookService(@Qualifier("bookdao02") IBookDAO daoofbook) {
this.daoofbook=daoofbook;
}*/
public void storeBook(String bookname){
System.out.println("图书上货");
String result=daoofbook.addBook(bookname);
System.out.println(result);
}
}
测试运行
package com.zhangguo.Spring051.ioc03;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
@org.junit.Test
public void testStoreBook()
{
//容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("IOCBeans03.xml");
BookService bookservice=ctx.getBean(BookService.class);
bookservice.storeBook("《Spring MVC权威指南 第三版》");
}
}
运行结果:
IBookDao
package spring12;
/**图书数据访问接口*/
public interface IBookDao {
/**添加新书*/
void save(String name);
}
BookDao
package spring12;
import org.springframework.stereotype.Repository;
/**
* 完成图书数据访问
*/
@Repository
public class BookDao implements IBookDao {
public void save(String name) {
System.out.println("添加图书" + name + "到数据库成功!");
}
}
BookService
package spring12;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
@Autowired
IBookDao bookDao;
/**新增一本书*/
public void addNewBook(){
String bookname="《Spring MVC学习指南》";
bookDao.save(bookname);
}
}
配置bookbean12.xml
BookStore
package spring12;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class BookStore {
@Autowired
BookService service;
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bookbean12.xml");
BookStore store =ctx.getBean(BookStore.class);
store.service.addNewBook();
}
}
测试结果:
@Qualifier("XXX") 中的 XX是 Bean 的名称,所以 @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。qualifier的意思是合格者,通过这个标示,表明了哪个实现类才是我们所需要的
先看下面这个示例:
package spring13;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
@Service
public class QualifierTest {
@Autowired
IBookDao dao;
public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext("bookbean13.xml");
QualifierTest obj = ctx.getBean(QualifierTest.class);
System.out.println(obj.dao);
}
}
interface IBookDao {
}
@Repository
class BookDaoA implements IBookDao {
}
@Repository
class BookDaoB implements IBookDao {
}
运行结果:
这样报错的原因是找到了多个Bean,Spring不知道选择那一个。使用Qualifier指定名称
package spring13;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
@Service
public class QualifierTest {
@Autowired
@Qualifier("daoA")
IBookDao dao;
public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext("bookbean13.xml");
QualifierTest obj = ctx.getBean(QualifierTest.class);
System.out.println(obj.dao);
}
}
interface IBookDao {
}
@Repository("daoA")
class BookDaoA implements IBookDao {
}
@Repository("daoB")
class BookDaoB implements IBookDao {
}
结果:
说明:本文限于篇幅,故而只展示部分的jvm内容,完整的JVM学习文档小编已经帮你整理好了,需要的朋友点赞+关注私信我777免费领取Java知识与技巧、课件,源码,安装包等等等还有大厂面试学习资料哦!