spring----06 更多DI知识

一. 延迟初始化

延迟初始化也叫做惰性初始化,指不提前初始化Bean,而是只有在真正使用时才创建及初始化Bean。
配置方式很简单只需在<bean>标签上指定 lazy-init” 属性值为“true”即可延迟初始化Bean

       Spring容器会在创建容器时提前初始化“singleton”作用域的Bean,“singleton”就是单例的意思即整个容器 每个Bean只有一个实例,后边会详细介绍。Spring容器预先初始化Bean通常能帮助我们提前发现配置错误,所以如果 没有什么情况建议开启,除非有某个Bean可能需要加载很大资源,而且很可能在整个应用程序生命周期中很可能使用不 到,可以设置为延迟初始化。
延迟初始化的Bean通常会在第一次使用时被初始化;或者在被非延迟初始化Bean作为依赖对象注入时在会随着初 始化该Bean时被初始化,因为在这时使用了延迟初始化Bean。
      容器管理初始化Bean消除了编程实现延迟初始化,完全由容器控制,只需在需要延迟初始化的Bean定义上配置即 可,比编程方式更简单,而且是无侵入代码的。

<bean id="helloApi"  
class="cn.javass.spring.chapter2.helloworld.HelloImpl"  
lazy-init="true"/>

二. 使用depends-on

depends-on是指指定Bean初始化及销毁时的顺序,使用depends-on属性指定的Bean要先初始化完毕后才初始 化当前Bean,由于只有“singleton”Bean能被Spring管理销毁,所以当指定的Bean都是“singleton”时,使用 depends-on属性指定的Bean要在指定的Bean之后销毁.

<bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>  
<bean id="decorator"  class="cn.javass.spring.chapter3.bean.HelloApiDecorator"  depends-on="helloApi">  <property name="helloApi"><ref bean="helloApi"/></property>  
</bean>  

说明:“decorator”指定了“depends-on”属性为“helloApi”,所以在“decorator”Bean初始化之前要先初始化 “helloApi”,而在销毁“helloApi”之前先要销毁“decorator”。

“depends-on”属性可以指定多个Bean,若指定多个Bean可以用“;”、“,”、空格分割。

那“depends-on”有什么好处呢?主要是给出明确的初始化及销毁顺序,比如要初始化“decorator”时要确保 “helloApi”Bean的资源准备好了,否则使用“decorator”时会看不到准备的资源;而在销毁时要先在 “decorator”Bean的把对“helloApi”资源的引用释放掉才能销毁“helloApi”,否则可能销毁 “helloApi”时而 “decorator”还保持着资源访问,造成资源不能释放或释放错误。

举例说明:

,在平常开发中我们可能需要访问文件系统,而文件打开、关闭是必须配对的,不能打开后不关 闭,从而造成其他程序不能访问该文件。让我们来看具体配置吧:

1. 准备测试类:

 1 public class ResourceBean {  
 2     private FileOutputStream fos;     
 3     private File file;  
 4     //初始化方法  
 5     public void init() {  
 6         System.out.println("ResourceBean:========初始化");  
 7         //加载资源,在此只是演示  
 8         System.out.println("ResourceBean:========加载资源,执行一些预操作");  
 9         try {  
10             this.fos = new FileOutputStream(file);  
11         } catch (FileNotFoundException e) {  
12             e.printStackTrace();  
13         }  
14     }  
15     //销毁资源方法  
16     public void destroy() {  
17         System.out.println("ResourceBean:========销毁");  
18         //释放资源  
19         System.out.println("ResourceBean:========释放资源,执行一些清理操作");  
20         try {  
21             fos.close();  
22         } catch (IOException e) {  
23             e.printStackTrace();  
24         }  
25     }  
26     public FileOutputStream getFos() {  
27         return fos;  
28     }  
29     public void setFile(File file) {  
30         this.file = file;  
31     }  
32 }  
View Code
 1 public class DependentBean {  
 2     ResourceBean resourceBean;     
 3     public void write(String ss) throws IOException {  
 4         System.out.println("DependentBean:=======写资源");  
 5         resourceBean.getFos().write(ss.getBytes());  
 6     }  
 7     //初始化方法  
 8     public void init() throws IOException {  
 9         System.out.println("DependentBean:=======初始化");  
10 resourceBean.getFos().write("DependentBean:=======初始化=====".getBytes());  
11     }  
12     //销毁方法  
13     public void destroy() throws IOException {  
14         System.out.println("DependentBean:=======销毁");  
15         //在销毁之前需要往文件中写销毁内容  
16         resourceBean.getFos().write("DependentBean:=======销毁=====".getBytes());  
17     }  
18      
19     public void setResourceBean(ResourceBean resourceBean) {  
20         this.resourceBean = resourceBean;  
21     }  
22 } 
View Code

说明:

ResourceBean从配置文件中配置文件位置,然后定义初始化方法init中打开指定的文件,然后获取文件流;最后定义销 毁方法destroy用于在应用程序关闭时调用该方法关闭掉文件流。

DependentBean中会注入ResourceBean,并从ResourceBean中获取文件流写入内容;定义初始化方法init用来定义 一些初始化操作并向文件中输出文件头信息;最后定义销毁方法用于在关闭应用程序时想文件中输出文件尾信息。

2. 准备配置文件

<bean id="resourceBean"  class="cn.javass.spring.chapter3.bean.ResourceBean"  init-method="init" destroy-method="destroy">  <property name="file" value="D:/test.txt"/>  
</bean>  
<bean id="dependentBean"  class="cn.javass.spring.chapter3.bean.DependentBean"  init-method="init" destroy-method="destroy" depends-on="resourceBean">  <property name="resourceBean" ref="resourceBean"/>  
</bean>  

     <property name="file" value="D:/test.txt"/>配置:Spring容器能自动把字符串转换为java.io.File。

      init-method="init" 指定初始化方法,在构造器注入和setter注入完毕后执行。     

      destroy-method="destroy"指定销毁方法,只有“singleton”作用域能销毁,“prototype”作用域的一定不能,其他作用域不一定能;后边再介绍。

在此配置中,resourceBean初始化在dependentBean之前被初始化,resourceBean销毁会在dependentBean销 毁之后执行。

3. 测试

 1 public class MoreDependencyInjectTest {  
 2     @Test  
 3     public void testDependOn() throws IOException {  
 4         ClassPathXmlApplicationContext context =  
 5 new ClassPathXmlApplicationContext("chapter3/depends-on.xml");  
 6         //一点要注册销毁回调,否则我们定义的销毁方法不执行  
 7         context.registerShutdownHook();  
 8         DependentBean dependentBean =  
 9 context.getBean("dependentBean", DependentBean.class);  
10         dependentBean.write("aaa");  
11     }  
12 } 
View Code

测试跟其他测试完全一样,只是在此我们一定要注册销毁方法回调,否则销毁方法不会执行。
如果配置没问题会有如下输出:

1 ResourceBean:========初始化  
2 ResourceBean:========加载资源,执行一些预操作  
3 DependentBean:=========初始化  
4 DependentBean:=========写资源  
5 DependentBean:=========销毁  
6 ResourceBean:========销毁  
7 ResourceBean:========释放资源,执行一些清理操作  
View Code

三. 自动装配

自动装配就是指由Spring来自动地注入依赖对象,无需人工参与。

目前Spring3.0支持“no”、“byName ”、“byType”、“constructor”四种自动装配,默认是“no”指不支 持自动装配的,其中Spring3.0已不推荐使用之前版本的“autodetect”自动装配,推荐使用Java 5+支持的 (@Autowired)注解方式代替;如果想支持“autodetect”自动装配,请将schema改为“spring-beans-2.5.xsd” 或去掉

自动装配的好处是减少构造器注入和setter注入配置,减少配置文件的长度。自动装配通过配置<bean>标签的 “autowire”属性来改变自动装配方式。接下来让我们挨着看下配置的含义。

表示使用默认的自动装配,默认的自动装配需要在<beans>标签中使用default-autowire属性指 定,其支持“no”、“byName ”、“byType”、“constructor”四种自动装配,如果需要覆盖默认自动装配,请 继续往下看;

1. no

意思是不支持自动装配,必须明确指定依赖。

2. byName

通过设置Bean定义属性autowire="byName",意思是根据名字进行自动装配,只能用于setter注 入。比如我们有方法“setHelloApi”,则“byName”方式Spring容器将查找名字为helloApi的Bean并注入,如果找 不到指定的Bean,将什么也不注入。

<bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>  
<bean id="bean" class="cn.javass.spring.chapter3.bean.HelloApiDecorator"  autowire="byName"/>  note:这里的byName的意思是上面的bean id="helloApi"必须和HelloApiDecorator类中的依赖类HelloImpl的名字一致,private HelloImpl helloApi;
1 public class AutowireBeanTest {  
2    @Test  
3     public void testAutowireByName() throws IOException {  
4 ClassPathXmlApplicationContext context =  
5 new ClassPathXmlApplicationContext("chapter3/autowire-byName.xml");  
6         HelloApi helloApi = context.getBean("bean", HelloApi.class);  
7         helloApi.sayHello();  
8     }  
9 }  
View Code

是不是不要配置<property>了,如果一个bean有很多setter注入,通过“byName”方式是不是能减少很多 <property>配置。此处注意了,在根据名字注入时,将把当前Bean自己排除在外:比如“hello”Bean类定义了 “setHello”方法,则hello是不能注入到“setHello”的。

3. byType

通过设置Bean定义属性autowire="byType",意思是指根据类型注入,用于setter注入,比如 如果指定自动装配方式为“byType”,而“setHelloApi”方法需要注入HelloApi类型数据,则Spring容器将查找 HelloApi类型数据,如果找到一个则注入该Bean,如果找不到将什么也不注入,如果找到多个Bean将优先注入 <bean>标签“primary”属性为true的Bean,否则抛出异常来表明有个多个Bean发现但不知道使用哪个。让我们用例 子来讲解一下这几种情况吧。

在根据类型注入时,将把当前Bean自己排除在外(note:byType时,就不需要helloApi必须和依赖属性名一样了,只和类型有关系,因此将上面的例子中byName改成byType就可以直接运行了)

note:

通过设置Bean定义的“autowire-candidate”属性为false来把指定Bean后自动装配候选者中移除:

<bean class="cn.javass.spring.chapter2.helloworld.HelloImpl" autowire-candidate="false"/> 

4. constructor

:通过设置Bean定义属性autowire="constructor",功能和“byType”功能一样,根据类 型注入构造器参数,只是用于构造器注入方式,直接将上面例子的byName改成constructor就好了

5. 全局自动装配

可以采用在“<beans>”标签中通过“default-autowire”属性指定全局的自动装配方式,即如果defaultautowire=”byName”,将对所有Bean进行根据名字进行自动装配。

6. 不是所有类型都能自动装配

  • 不能自动装配的数据类型:Object、基本数据类型(Date、CharSequence、Number、URI、URL、Class、int)等;
  • 通过“<beans>”标签default-autowire-candidates属性指定的匹配模式,不匹配的将不能作为自动装配的候选者,例如指定“*Service,*Dao”,将只把匹配这些模式的Bean作为候选者,而不匹配的不会作为候选者;
  • 通过将“<bean>”标签的autowire-candidate属性可被设为false,从而该Bean将不会作为依赖注入的候选者。

7. 数组、集合、字典类型的根据类型自动装配和普通类型的自动装配是有区别的:

  • 数组类型、集合(Set、Collection、List)接口类型:将根据泛型获取匹配的所有候选者并注入到数组或集合中,如“List<HelloApi> list”将选择所有的HelloApi类型Bean并注入到list中,而对于集合的具体类型将只选择一个候选者,“如 ArrayList<HelloApi> list”将选择一个类型为ArrayList的Bean注入,而不是选择所有的HelloApi类型Bean进行注入;
  • 字典(Map)接口类型:同样根据泛型信息注入,键必须为String类型的Bean名字,值根据泛型信息获取,如“Map<String, HelloApi> map” 将选择所有的HelloApi类型Bean并注入到map中,而对于具体字典类型如“HashMap<String, HelloApi> map”将只选择类型为HashMap的Bean注入,而不是选择所有的HelloApi类型Bean进行注入。

8. 自动装配的优缺点

      优点:首先,自动装配确实减少了配置文件的量;其次, “byType”自动装配能在相应的Bean更改了字段类型时自动更新,即修改Bean类不需要修改配置,确实简单了。

       缺点:最重要的缺点就是没有了配置,在查找注入错误时非常麻烦,还有比如基本类型没法完成自动装配,所以可能经常发生一些莫名其妙的错误,在此我推荐大家不要使用该方式,最好是指定明确的注入方式,或者采用最新的Java5+注解注入方式。所以大家在使用自动装配时应该考虑自己负责项目的复杂度来进行衡量是否选择自动装配方式。

       自动装配注入方式能和配置注入方式一同工作吗?当然可以,大家只需记住配置注入的数据会覆盖自动装配注入的数据。

 

9. 依赖检查

上一节介绍的自动装配,很可能发生没有匹配的Bean进行自动装配,如果此种情况发生,只有在程序运行过程中 发生了空指针异常才能发现错误,如果能提前发现该多好啊,这就是依赖检查的作用。

依赖检查:用于检查Bean定义的属性都注入数据了,不管是自动装配的还是配置方式注入的都能检查,如果没有注入数 据将报错,从而提前发现注入错误,只检查具有setter方法的属性。
Spring3+也不推荐配置方式依赖检查了,建议采用Java5+ @Required注解方式,测试时请将XML schema降低为2.5 版本的,和自动装配中“autodetect”配置方式的xsd一样。

依赖检查有none、simple、object、all四种方式,接下来让我们详细介绍一下:

(1)none

默认方式,表示不检查

(2)objects

:检查除基本类型外的依赖对象,配置方式为:dependency-check="objects",此处我们为 HelloApiDecorator添加一个String类型属性“message”,来测试如果有简单数据类型的属性为null,也不报错;

<bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>  
<!-- 注意我们没有注入helloApi,所以测试时会报错 -->  
<bean id="bean"  class="cn.javass.spring.chapter3.bean.HelloApiDecorator"  dependency-check="objects">  
<property name="message" value="Haha"/>  
</bean>  

注意由于我们没有注入bean需要的依赖“helloApi”,所以应该抛出异常UnsatisfiedDependencyException,表示没有发现满足的依赖:

public class DependencyCheckTest {  
@Test(expected = UnsatisfiedDependencyException.class)  
public void testDependencyCheckByObject() throws IOException {  
//将抛出异常  new ClassPathXmlApplicationContext("chapter3/dependency-check-object.xml");  }  
}  

(3)simple

对基本类型进行依赖检查,包括数组类型,其他依赖不报错;配置方式为:dependency-check="simple",以下配置中没有注入message属性,所以会抛出异常:

<bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>  
<!-- 注意我们没有注入message属性,所以测试时会报错 -->  
<bean id="bean"  
class="cn.javass.spring.chapter3.bean.HelloApiDecorator"  dependency-check="simple">  <property name="helloApi" ref="helloApi"/>  
</bean>  

(4)all

对所以类型进行依赖检查,配置方式为:dependency-check="all",如下配置方式中如果两个属性其中一个没配置将报错。

<bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>  
<bean id="bean"  
class="cn.javass.spring.chapter3.bean.HelloApiDecorator"  dependency-check="all">  <property name="helloApi" ref="helloApi"/>  
<property name="message" value="Haha"/>  
</bean>  

依赖检查也可以通过“<beans>”标签中default-dependency-check属性来指定全局依赖检查配置。

 

参考文献:

https://jinnianshilongnian.iteye.com/blog/1415461

 

转载于:https://www.cnblogs.com/Hermioner/p/10193125.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/426090.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Leedcode][JAVA][第1162题][BFS]

【问题描述】 你现在手里有一份大小为 N x N 的『地图』&#xff08;网格&#xff09; grid&#xff0c;上面的每个『区域』&#xff08;单元格&#xff09;都用 0 和 1 标记好了。其中 0 代表海洋&#xff0c;1 代表陆地&#xff0c;你知道距离陆地区域最远的海洋区域是是哪一…

java学习(133):泛型

public class Employee {private String name;private String ags;public void setName(String name) {this.name name;}public String getName() {return name;}public void setAgs(String ags) {this.ags ags;}public String getAgs() {return ags;} }测试类 import java.…

【软考】[信息安全工程师]

【背景】 有一定的基础&#xff0c;于2019年5月的考试上岸&#xff0c;复习了两周左右。奥里给&#xff01; 【备考资料】 【参考网站】 信管网 http://www.cnitpm.com/aq/ 月梦工作室 https://www.moondream.cn/ 含历年试题以及参考答案 【参考教材】 信息安全工程师五天…

java学习(134):泛型通配符的使用

import java.util.ArrayList; import java.util.List;//泛型通配符的使用 public class test73 {public static void main(String[] args){List<Integer> intListnew ArrayList<Integer>();intList.add(new Integer(100));intList.add(new Integer(200));List<?…

java dictionary遍历_遍历 Dictionary,你会几种方式?

一&#xff1a;背景1. 讲故事昨天在 StackOverflow 上看到一个很有趣的问题&#xff0c;说: 你会几种遍历字典的方式&#xff0c;然后跟帖就是各种奇葩的回答&#xff0c;挺有意思&#xff0c;马上就要国庆了&#xff0c;娱乐娱乐吧&#xff0c;说说这种挺无聊的问题&#x1f6…

密码系统的安全性

1&#xff0c;评估密码系统安全性主要有三种方法&#xff1a; &#xff08;1&#xff09;无条件安全性 这种评价方法考虑的是假定攻击者拥有无限的计算资源&#xff0c;但仍然无法破译该密码系统。 &#xff08;2&#xff09;计算安全性 这种方法是指使用目前最好的方法攻破…

java两种绑定方式_Javascript绑定事件的两种方式的区别

命名函数function check(){//code}匿名函数window.onload function(){//先获取元素对象&#xff0c;再绑定事件&#xff0c;绑定的是匿名函数不可重用var btn document.getElementById("btn");btn.onclick function(){//code}}以前一直以为两种方式的区别不大&…

前端基础_认识前端.md

前端学习 前端学习路线学习网站 菜鸟驿站慕课网freeCOdeCampw3schooltry8在线编辑 codepenjsfiddlethecodeplayer其他网站 cssfilterscssstats极客学院搭建个人博客wordpress博客园网站检查规范How to learn webTobe continue... 学习准备 查看浏览器占有的市场份额 查看浏览器…

[剑指offer][JAVA][第62题][约瑟夫环][LinkedList vs ArrayList]

【问题描述】 面试题62. 圆圈中最后剩下的数字 0,1,,n-1这n个数字排成一个圆圈&#xff0c;从数字0开始&#xff0c;每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。例如&#xff0c;0、1、2、3、4这5个数字组成一个圆圈&#xff0c;从数字0开始每次删除第…

java学习(136):带泛型的类

SuppressWarnings("all") public class GJClass<T> {public String getClassName(T t){return t.getClass().getName();} } 测试类 public class test76 {public static void main(String[] args){GJClass gjClassnew GJClass();String classNamegjClass.get…

如何往eclipse中导入maven项目

现在公司中大部分项目可能都是使用maven来构建&#xff0c;假如现在摆在你面前有一个maven的项目&#xff0c;如果你要学习它&#xff0c;如何将它导入到像eclipse这样的集成开发工具中呢&#xff0c;以项目public_class_1为例&#xff1a; 1.在eclipse的工作界面的最左侧&…

[Leetcode][JAVA][第1111题][栈思想]

【问题描述】 有效括号字符串 定义&#xff1a;对于每个左括号&#xff0c;都能找到与之对应的右括号&#xff0c;反之亦然。详情参见题末「有效括号字符串」部分。嵌套深度 depth 定义&#xff1a;即有效括号字符串嵌套的层数&#xff0c;depth(A) 表示有效括号字符串 A 的嵌…

java学习(137):java异常初识

//java异常初识 public class test78 {public static void main(String[] args) {countArraylength( -1 );}public static int countArraylength(int length) {int[] nums new int[length];return nums.length;} } 运行结果

Java如何随机出石头剪刀布_JAVA编程实现石头剪刀布

我不是焊工import java.util.Scanner;public class Jsb {public static void main(String[] args) {while (true) {result(input(), random());System.out.println("");}}public static int input() {System.out.println("请输入&#xff1a;1-剪刀&#xff0c;…

java学习(138):异常处理

//异常 public class test79 {//定义方法声明定义异常&#xff0c;在满足条件时抛出异常对象&#xff0c;程序转向异常处理public double count(double n,double m)throws Exception {if (m 0) {//如果除数等于0.则抛出异常实例throw new Exception("对不起。除数不能等…

java学习(139):多个catch块

import java.sql.Connection;import java.io.IOException; import java.sql.SQLException;//java异常处理 //异常 public class test82 {//定义方法声明定义异常&#xff0c;在满足条件时抛出异常对象&#xff0c;程序转向异常处理public double count(double n, double m, Con…

[Leedcode][JAVA][第289题][生命游戏]

【问题描述】 根据 百度百科 &#xff0c;生命游戏&#xff0c;简称为生命&#xff0c;是英国数学家约翰何顿康威在 1970 年发明的细胞自动机。给定一个包含 m n 个格子的面板&#xff0c;每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态&#xff1a;1 即为活细…

java学习(140):1.7后新特性

import java.sql.Connection;import java.io.IOException; import java.sql.SQLException;//java异常处理 //异常 public class test82 {//定义方法声明定义异常&#xff0c;在满足条件时抛出异常对象&#xff0c;程序转向异常处理public double count(double n, double m, Con…

[剑指offer]面试题第[67]题[Leetcode][JAVA][第8题] 字符串转换整数 (atoi)[字符串]

【问题描述】 请你来实现一个 atoi 函数&#xff0c;使其能将字符串转换成整数。首先&#xff0c;该函数会根据需要丢弃无用的开头空格字符&#xff0c;直到寻找到第一个非空格的字符为止。接下来的转化规则如下&#xff1a;如果第一个非空字符为正或者负号时&#xff0c;则将…

java学习(141):自定义捕捉异常

//自定义异常类 public class ArrayElement extends Exception{public static final int MAX_NUM1000;private static final String MESSAGE"集合存储元素过多";public ArrayElement(){}public String getMessage(){return MESSAGE"最大元素限制为"MAX_NU…