在项目开发中如果我们通过在xml文件内部注册bean给spring容器的形式,那么如果需要注册的bean过多怎么办?一千行一万行的代码非常不便于阅读,因为我们除了注册bean之外还需要在主配置文件中配置其他的东西,那么配置信息就更难以阅读了。于是spring提供了一种早期的分布式文件系统思想,我们将所有bean标签单独移动到一个xml中,然后在applicationConetxt.xml引入这个xml文件,下面请看代码是如何实现的。
可以看到主配置文件已经非常干净了,那么bean标签都去哪里了呢?别急,先看图中红框标识出的是什么呢.ContextModel,内容model,这里是一个标签的载入顺序,最先载入的是我们xml的description部分,也就是xsd约束。接下来,载入的是import标签,该标签能够将其他配置文件关联至本页面,相当于这里创建了一个另一个xml的引用,它的属性只有一个,就是resource,里面写需要引入的配置稳健的相对路径,这样看起来就清爽了许多。
那么我觉得在xml中配置bean太过于麻烦了,有没有其他简单的方法?有,spring同时提供了一种通过注解来创建bean,为属性注入的方式。先看上图的
这是user注册bean的配置,这么大一坨,下面看看通过注解注册有多少行代码
答案一目了然,只有四个单词,替代了整整一大坨的xml配置方式,注解也是现在的主流开发方式。下面让我们来认识一下这些注解是什么意思,@Component: 组件,在类名上方使用此注解能够将该类注册到Sping容器中,从而创建实例,同时结合spring的分成思想,又提供了另外三个与@Component功能一模一样的注解,分别用于三层中。*@Controller :WEB 层,@Service :服务层@Repository :持久层,这三个注册除了能够Component本身功能外,还起到一定的标识作用,表名该类的用途。
注解对IOC的支持结束后,下面看看对DI怎么使用。我们使用@value注解对基本数据类型进行注入,使用起来比较简单在括号内写入需要注入的值即可,但是注入的值类型必须符合变量类型,就是说如果变量是个int类型,不能写String进去。那么对象类型该怎么注入呢?使用@Autowired,该标签通过对象的类型注入实例,实现原理是:比如我变量类型为User,那么spring会在容器中寻找类型为user的实例,找到了就注入到变量中。它有一个要求,注入的对象必须是被注册到spring容器中的bean,否则无法完成注入。那么如果出现多个与变量类型匹配的对象spring应该注入哪一个呢?见下图
那么这里我们使用scope标签就User2的作用范围指定为prototype多例,会发生什么呢?spring就会不知道应该为User1中变量注入哪一个对象了,这时spring提供了两种解决方案
组合使用@Autowired@Qualifier标签,@Qualifier标签能够在@Autowired给的类型内部指定变量名称。而@Resource能够直接指定需要注入的变量名称,@Resource一个标签能够替代@Autowired@Qualifier两个标签,所以建议在注入对象为单例情况下,建议使用@Autowired标签,可能为多例的情况下使用@Resource标签。下面执行以下程序打印对象看看结果
程序正确执行了,但是红框标出来的值缺不是我之前在上图通过@Value注入的值,这是为什么呢?
大家看到@PostConstruct和@PreDestroy注解,会想到这两个做什么的呢?这两个注解就像鱼bean标签中的,init-method和destroy-method,原来bean中的任一属性都有相对应的注解来实现,不过上面输出了我设置的当前系统时间,说明了什么?是我的注解@value没有生效吗,并不是,而这里恰恰说明一个问题,init方法是在spring对phoneNumber变量赋值后才执行的,为了证实这一猜想我们进行如下测试
在对phoneNumber赋值之前打印,以证实@value注解是否生效,可以猜测一下执行结果看看下图是否如你所想
看到打印结果证明@value注解正常执行,init方法确实是在spring注入之后执行。那么为什么为执行了三次init方法呢?下面我将会标识出,对user2进行访问的代码
此处创建User2引用并通过@Resource注入时,创建了一个user2实例,执行了一次init方法。
此处创建User2引用并通过@Resource注入时,创建了一个user2实例,执行了一次init方法。不过在我的User3类中@Resource注解并没有指定name,为什么也能够完成注入呢?@Resource标签在不指定name时,默认寻找类型名称首字母小写的变量。比如我有一个类叫YUD,那么@Resource不指定name时,默认名寻找yUD的变量。
最后一次对User2的访问xml中对集合进行注入时,注入了一个user2,也就是如果User2的范围是prototype时,每次访问都会生成新的对象,而scope为singleton单例时,每次访问都为同一对象,init方法也会只执行一次。
那么当我们手动关闭容器时,它的destory方法会发生怎么样的变化呢?
手动关闭容器时,当bean的范围为单例singleton时,destory方法会执行一次.当scope为prototype多例时,destory方法不会被执行,也就是说只有单例的情况下spring容器才会回收bean对象,否则由Jvm进行回收。
此外补充一点,在spring环境下有些人的@Resource标签可能无法使用,因为这个标签是J2EE的标签,我们需要通过maven引入javax拓展包下的annotation依赖即可。
以上就是spring通过注解的方式进行IOC,DI操作了,是不是很方便呢?请在评论区留下你的看法把!