(转)Spring实现IoC的多种方式
原文地址:http://www.cnblogs.com/best/p/5727935.html
目录
- 一、使用XML配置的方式实现IOC
- 二、使用Spring注解配置IOC
- 三、自动装配
- 四、零配置实现IOC
- 五、示例下载
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中我们使用面向对象编程对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获取依赖对象的方式反转了。
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
一、使用XML配置的方式实现IOC
假设项目中需要完成对图书的数据访问服务,我们定义好了IBookDAO接口与BookDAO实现类
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如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.zhangguo</groupId><artifactId>Spring051</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>Spring051</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring.version>4.3.0.RELEASE</spring.version></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope><version>4.10</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.9</version></dependency><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.4</version></dependency></dependencies> </project>
业务类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的beanbookDAO=(IBookDAO)ctx.getBean("bookdao");}public void storeBook(String bookname){System.out.println("图书上货");String result=bookDAO.addBook(bookname);System.out.println(result);} }
容器的配置文件IOCBeans01.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" xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="bookdao" class="com.zhangguo.Spring051.ioc01.BookDAO"></bean> </beans>
测试类Test如下:
package com.zhangguo.Spring051.ioc01;public class Test {@org.junit.Testpublic void testStoreBook(){BookService bookservice=new BookService();bookservice.storeBook("《Spring MVC权威指南 第一版》");} }
运行结果:
二、使用Spring注解配置IOC
上一个示例是使用传统的xml配置完成IOC的,如果内容比较多则配置需花费很多时间,通过注解可以减轻工作量,但注解后修改要麻烦一些,偶合度会增加,应该根据需要选择合适的方法。
2.1、修改BookDAO
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 相同。
2.2、修改BookService
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的beanbookDAO=(IBookDAO)ctx.getBean("bookdaoObj");System.out.println("图书上货");String result=bookDAO.addBook(bookname);System.out.println(result);} }
将构造方法中的代码直接写在了storeBook方法中,避免循环加载的问题。
2.3、修改IOC配置文件IOCBeans02.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" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.3.xsd"><context:component-scan base-package="com.zhangguo.Spring051.ioc02"></context:component-scan> </beans>
粗体字是新增的xml命名空间与模式约束文件位置。增加了注解扫描的范围,指定了一个包,可以通过属性设置更加精确的范围如:
<context>标记常用属性配置:
resource-pattern:对指定的基包下面的子包进行选取
<context>子标记:
include-filter:指定需要包含的包
exclude-filter:指定需要排除的包
<!-- 自动扫描com.zhangguo.anno.bo中的类进行扫描 -->
<context:component-scan base-package="com.zhangguo.anno" resource-pattern="bo/*.class" />
<context:component-scan base-package="com.zhangguo.anno" >
<context:include-filter type="aspectj“ expression="com.zhangguo.anno.dao.*.*"/>
<context:exclude-filter type=“aspectj” expression=“com.zhangguo.anno.entity.*.*”/>
</context:component-scan>
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 | 通过代码过滤,实现org.springframework.core.type.TypeFilter接口 |
expression表示过滤的表达式。
<!-- 1、如果仅希望扫描特定的类而非基包下的所有类,可使用resource-pattern属性过滤特定的类 --><context:component-scan base-package="com.zhangguo.Spring051"resource-pattern="ioc04/A*.class"></context:component-scan>
只扫描com.zhangguo.Spring051.ioc04下所有名称以A开始的类。
<!--2、扫描注解了org.springframework.stereotype.Repository的类exclude-filter表示排除,include-filter表示包含,可以有多个--><context:component-scan base-package="com.zhangguo.Spring051.ioc04"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository" /><context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/></context:component-scan>
<!--3、aspectj类型,扫描dao下所有的类,排除entity下所有的类--><context:component-scan base-package="com.zhangguo.anno" ><context:include-filter type="aspectj" expression="com.zhangguo.anno.dao.*.*"/><context:exclude-filter type="aspectj" expression="com.zhangguo.anno.entity.*.*"/> </context:component-scan>
2.4、测试类
package com.zhangguo.Spring051.ioc02;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {@org.junit.Testpublic void testStoreBook(){//容器ApplicationContext ctx=new ClassPathXmlApplicationContext("IOCBeans02.xml");BookService bookservice=ctx.getBean(BookService.class);bookservice.storeBook("《Spring MVC权威指南 第二版》");} }
运行结果:
2.5、小结
从配置文件中我们可以看出我们并没有声明bookdaoObj与BookService类型的对象,但还是从容器中获得了实例并成功运行了,原因是:在类的开头使用了@Component注解,它可以被Spring容器识别,启动Spring后,会自动把它转成容器管理的Bean。
三、自动装配
从上一个示例中可以看出有两个位置都使用了ApplicationContext初始化容器后获得需要的Bean,可以通过自动装配简化。
3.1、修改BookDAO
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更贴切一些,非必要。
3.2、修改BookService
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 {@AutowiredIBookDAO 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);} }
3.3、测试运行
package com.zhangguo.Spring051.ioc03;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {@org.junit.Testpublic void testStoreBook(){//容器ApplicationContext ctx=new ClassPathXmlApplicationContext("IOCBeans03.xml");BookService bookservice=ctx.getBean(BookService.class);bookservice.storeBook("《Spring MVC权威指南 第三版》");} }
运行结果:
四、零配置实现IOC
所谓的零配置就是不再使用xml文件来初始化容器,使用一个类型来替代,
IBookDAO代码如下:
package com.zhangguo.Spring051.ioc06;/*** 图书数据访问接口*/ public interface IBookDAO {/*** 添加图书*/public String addBook(String bookname); }
IBookDAO的实现类BookDAO代码如下:
package com.zhangguo.Spring051.ioc06;import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository;/*** 图书数据访问实现类*/ @Repository public class BookDAO implements IBookDAO {public String addBook(String bookname) {return "添加图书"+bookname+"成功!";} }
在BookDAO类上注解了@Repository当初始化时该类将被容器管理会生成一个Bean,可以通过构造方法测试。
业务层BookService代码如下:
package com.zhangguo.Spring051.ioc06;import javax.annotation.Resource;import org.springframework.stereotype.Service;/*** 图书业务类*/ @Service public class BookService {@ResourceIBookDAO bookDAO;public void storeBook(String bookname){System.out.println("图书上货");String result=bookDAO.addBook(bookname);System.out.println(result);} }
类BookService将对容器管理因为注解了@Service,初始化时会生成一个单例的Bean,类型为BookService。在字段bookDAO上注解了@Resource,用于自动装配,Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。
新增一个用于替代原xml配置文件的ApplicationCfg类,代码如下:
package com.zhangguo.Spring051.ioc06;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;/*** 容器的配置类*/ @Configuration @ComponentScan(basePackages="com.zhangguo.Spring051.ioc06") public class ApplicationCfg {@Beanpublic User getUser(){return new User("成功");} }
@Configuration相当于配置文件中的<beans/>,ComponentScan相当于配置文件中的context:component-scan,属性也一样设置
,@Bean相当于<bean/>,只能注解在方法和注解上,一般在方法上使用,源码中描述:@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}),方法名相当于id。中间使用到了User,User类的代码如下:
package com.zhangguo.Spring051.ioc06;import org.springframework.stereotype.Component;@Component("user1") public class User {public User() {System.out.println("创建User对象");}public User(String msg) {System.out.println("创建User对象"+msg);}public void show(){System.out.println("一个学生对象!");} }
初始化容器的代码与以前有一些不一样,具体如下:
package com.zhangguo.Spring051.ioc06;import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Test {@org.junit.Testpublic void testStoreBook(){//容器,注解配置应用程序容器,Spring通过反射ApplicationCfg.class初始化容器ApplicationContext ctx=new AnnotationConfigApplicationContext(ApplicationCfg.class);BookService bookservice=ctx.getBean(BookService.class);bookservice.storeBook("《Spring MVC权威指南 第四版》");User user1=ctx.getBean("user1",User.class);user1.show();User getUser=ctx.getBean("getUser",User.class);getUser.show();} }
容器的初始化通过一个类型完成,Spring通过反射ApplicationCfg.class初始化容器,中间user1与getUser是否为相同的Bean呢?
答案是否定的,因为在ApplicationCfg中声明的方法getUser当相于在xml文件中定义了一个<bean id="getUser" class="..."/>,在User类上注解@Component("user1")相当于另一个<bean id="user1" class="..."/>。
运行结果:
小结:使用零配置和注解虽然方便,不需要编写麻烦的xml文件,但并非为了取代xml,应该根据实例需要选择,或二者结合使用,毕竟使用一个类作为容器的配置信息是硬编码的,不好在发布后修改。
五、示例下载
点击下载
转载于:https://www.cnblogs.com/lezhifang/p/6963646.html
(转)Spring实现IoC的多种方式相关推荐
- Spring学习总结(一)——Spring实现IoC的多种方式
一.Spring框架概述 Spring是一个开源免费的框架,为了解决企业应用开发的复杂性而创建.Spring框架是一个轻量级的解决方案,可以一站式地构建企业级应用.Spring是模块化的,所以可以只使 ...
- Spring的IOC创建对象的方式和代码基本解释为什么要有ioc的思维以及Ioc容器和spring依赖注入的解释
首先我们要知道 Ioc是个啥? IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合.更优良的程序.传统应用程序都是由我们在类内部主动创建依赖对象,从而导致 ...
- Spring学习总结——Spring实现AOP的多种方式
目录 一.基于XML配置的Spring AOP 二.使用注解配置AOP 三.AspectJ切点函数 四.AspectJ通知注解 五.零配置实现Spring IoC与AOP 六.示例下载 AOP(Asp ...
- Spring教程--IOC(注解方式)和整合junit
1 IOC装配Bean(注解方式) 1.1 Spring的注解装配Bean Spring2.5 引入使用注解去定义Bean @Component 描述Spring框架中Bean Spring的框架中 ...
- Spring之IOC的注入方式总结
林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 在定义了 JavaBean 装载信息之后需要对其赋值.一个 JavaBean 的赋值可以通过构 ...
- Spring属性注入的多种方式
随缘记录 方便记忆 1.通过setter方式注入 <property> 前提 该已提供setter方法 1.1 <!-- 使用setter方法注入数据 普通数据--> < ...
- Spring/Spring Boot错误页面处理的多种方式(404 not found等)
Spring/Spring Boot错误页面处理的多种方式(404 not found等) 简单来说, tomcat容器会根据error-page的内容forward到指定location(会再走一次 ...
- Spring的IoC理解,代码进行详解
如何理解Spring的IoC IOC底层原理 创建User实体类 创建了UserDao接口 创建了UserDaoImpl实现类 8.4 创建了UserService接口 创建了UserServiceI ...
- Spring之IOC(一)
一.概念和原理 1.什么是IOC (1)IOC:控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理. (2)使用 IOC 的目的:为了降低耦合度. 2.IOC底层原理 xml解析. ...
- Java注入bean的方式_多种方式实现Spring的Bean注入
Spring的核心是控制反转(IoC)和面向切面(AOP). Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理 . Spring工厂是用于生成Bean,对Be ...
最新文章
- python程序员的工作内容_每个Python程序员都要知道的日志实践
- C#实现Web应用程序定时启动任务
- Android NDK学习笔记3:JNI访问Java属性、方法
- 开源浪潮下程序员的职业规划和成长
- python多核运行程序怎么关闭_在多核上运行程序
- 关于Java的十件事
- 喂,你经历过两三年前的前端开发吗?
- SpringBootDubboZookeeper远程调用项目搭建
- 算法导论 练习9.3-8两个有序数组的中位数
- html常规的布局模版,html5/css3常规布局(示例代码)
- 调试错误:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
- 通信原理实践(五)——2PSK 与2DPSK 通信系统
- 基于Web的SQL Server管理工具(SQL Server Web Tools )
- 如何在同一Linux服务器上创建多站点
- 数字孪生智慧运维系统方案
- 小恐龙游戏python_自动玩Chrome浏览器的小恐龙游戏
- Python运行不显示DOS窗口方法
- 【2020】win10java(jdk安装)环境变量配置和相关问题解决
- 工程流体力学笔记暂记43 (收缩喷管中的流动)
- Java实现三角形图案绘制**