在Spring应该如何管理泛型bean
IOC依赖注入,配置bean。创建需要的实例,不过在相对应的类中应该有set方法。set注入比较方便,也简单。
private static ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/spring-servlet.xml"); public static Object getBean(String beanName){ return ctx.getBean(beanName); }
spring 配置bean 怎么使用
1、Bean的配置一般都在XML文件中进行配置
2、Bean相关包为:org.springframework.beans和org.springframework.context
3、spring的Bean管理的实现是依靠大量的反射来实现的。
4、Bean定义配置
4.1 Bean标签
▶id属性:用于指定Bean的名称,在Bean被依赖时使用,在获取Bean时使用等
▶name属性:用于指定Bean的别名
▶class属性:用于指定Bean的来源,即创建要创建的Bean的class类(需要全限定名)
▶singleton属性:用于指定当前Bean的创建模式,若值为true表示为单例模式,false表示原型模式(prototype)
▶depends-on属性:用于指定当前Bean的依赖Bean,强制指定的Bean在当前Bean初始化之前先完成初始化
▶init-method属性:用于指定当前Bean的初始化方法,在Bean实例创建好后,首先会调用其指定名称的方法
▶destory-method属性:用于指定当前Bean的销毁方法,在Bean即将被销毁之前会自动调用该属性指定的方法
▶lazy-init属性:用于指定当前Bean的初始化时间,若值为true表示在初次调用时才会自动创建实例并初始化,false表示在IoC容器创建的时候就会完成创建和初始化
▶autowire属性:用于指定当前Bean的依赖关系的自动注入方式,其有五个值:
▷byName值:表示通过id名称来自动匹配;
▷byType值:表示通过class指定的类型来自动装配;
▷constructor值:表示使用构造函数的参数进行自动装配(参数的类型匹配);
▷autodetect值:表示自动进行选择匹配方式,首先进行constructor自动装配,若不存在构造方法则使用byType方式进行自动装配;
▷no值:表示不适用自动装配。
▶dependency-check属性:用于指定Bean的依赖检查模式,检查依赖关系是否完整,与自动装配合用,其有四个值:
▷simple值:表示针对基本类型、字符串、集合进行依赖检查
▷object值:表示对引用对象进行依赖检查
▷all值:表示对基本类型、字符串、集合、引用对象全部进行依赖检查
▷none值:表示不进行任何依赖检查,默认情况。
Bean示例:
1 ?xml version=”1.0”encoding=”utf-8”?
2 !Doctype beans PUBLIC “-//SPRING//DTD BEAN//EN”
3 “”
4 beans
5 bean id=”helloworld” class=”com.dh.spring.HelloWorld” singleton=”true” depends-on=”date” lazy-init=”false” init-mathod=”init” destory-method=”destory”/
6 bean id=”date” class=”java.util.Date”/
7 /beans
4.2 property标签
▶name属性:用于指定属性的名称,与类中的set方法后方的名称一致
▶value属性:用于指定该属性的值,用于指定的值是基本类型、字符串类型
▶ref属性:用于指定该属性的值,用于指定的值是引用对象类型(即其他的Bean),ref后面的值为另一个Bean的id
▶value标签:用于指定属性的值,类型为基本类型、字符串类型,值为标签内的文本内容,可以使用null值将属性的值设置为null
▶ref标签:用于指定属性的值,类型为引用对象类型,值为其属性的值,其属性有以下三种:
▷local属性:用于指定依赖本地Bean实例,即同一XML文件中定义的Bean
▷bean属性:用于指定依赖的Bean实例,可以是不同XML文件中的Bean
▷parent属性:用于指定依赖的Bean实例,可以是当前BeanFactory或ApplicationContext的父BeanFactory或ApplicationContext中的Bean
以下是针对集合的标签
▶list标签:用于声明该依赖对象为一个list集合,其下用value和ref标签来指定list中的各值(基本、字符串、对象等)
▷value标签:用于指定list集合中的值,指定的值为基本类型、字符串类型,值为文本内容
▷ref标签:用于指定list集合中的引用值,指定的值为其他的对象Bean,其用法与之前property标签下的ref标签的用法相同
▶set标签:用于声明该依赖对象为一个set集合,其用法与list标签相同。
▶map标签:用于声明该依赖对象为一个map集合,其下用entry标签来声明一个键值对
▷entry标签:用于声明map集合下的一个键值对,其下用key属性指明键,value/ref标签指明值
→key属性:用于指明键值对中的键,它一般为字符串
→value标签:用于指明键值对中的值,类型为基本类型、字符串类型
→ref标签:用于指明键值对中的值,类型为引用对象类型,即其他的Bean,其用法同之前的ref标签
map实例1:
1 bean id=”helloworld” class=”com.dh.spring.HelloWorld”
2 property name=”pname”
3 map
4 entry key=”mkey1”
5 valuemvalue1/value
6 /entry
7 entry key=”mkey2”
8 valuemvalue2/value
9 /entry
10 /map
11 /property
12 /bean
map实例2:
1 bean id=”helloworld2” class=”com.dh.spring.HelloWorld2”
2 property name=”pname”
3 map
4 entry key=”mkey1”
5 ref bean=”helloworld”/
6 /entry
7 /map
8 /property
9 /bean
▶props标签:用于声明该依赖对象为一个properties集合,其下用prop标签来指定属性的名称及值(键值对)
▷prop标签:用于设置集合中的一个键值对
→key属性:用于指明键值对中的键,一般为字符串
→文本内容:用于指明键值对中的值,一般为字符串,不用加引号
props实例:
1 bean id=”helloword” class=”com.dh.spring.HelloWorld”
2 property name=”pname”
3 props
4 prop key=”pkey1”pvalue1/prop
5 prop key=”pkey2”pvalue2/prop
6 /props
7 /property
8 /bean
5、Bean的生命周期
Bean的生命周期包括Bean的定义,Bean的初始化,Bean的使用,Bean的销毁
Bean的定义:一般Bean使用XML文件的方式进行定义,定义的时候将Bean之间的依赖关系和属性的赋值都进行了定义
Bean的初始化:其实Bean的初始化包括Bean的创建和初始化两个方法,Bean的创建和初始化一般是同步进行的,Bean在完成创建后直接就会进行初始化操作,创建的时机与Bean的lazy-init属性的设置有关。
Bean的使用:在web程序运行期间,发生对某一个Bean的调用时,就会使用这个Bean实例,如果使用编码的方式来获取Bean同样也是Bean的使用,Bean的编码使用方式有三种,第一种是使用BeanWarpper,第二种是使用BeanFactory,第三种就是使用ApplicationContext。
Bean的销毁:Bean实例在程序退出的时候会进行销毁,而在销毁之前会自动调用Bean的destory-method属性指定名称的方法。
Spring注解方式管理Bean
虽然Spring以简化开发著称,但在学习的过程中我们发现,每新建一个类,就需要在配置文件中进行配置,并且类与类之间的关系也需要配置在标签中,好像这并没有简化我们的开发,反而增加了很多繁琐的配置。别担心,本篇文章我们就来学习一下用注解方式来管理Bean。
组件扫描
大家不要对组件这个词感到陌生,在Spring中,一个类可以被称为Bean,也被称为一个组件,回想一下,在之前,我们如何将一个组件注册到IOC容器中呢?没错,我们需要写一段配置,例如:
为了让大家从繁琐的配置中解脱出来,Spring提供了一种基于注解的管理方式,Spring提供了以下注解用来注册一个组件:
1.@Component2.@Controller3.@Service4.@Repository
这四个注解都可以用来注册一个组件,不过每个注解都有其意义,比如@Controller,它是用来注册一个前端控制器的,我们将在SpringMVC中对其进行详解;而@Service是用来注册一个服务层对象的;@Repository是用来注册一个持久层对象的。来体验一下它们的强大吧:
我们从容器中取出所有的组件,看看注册是否成功了:
当你运行这段测试代码时你会发现控制台没有任何输出,是我们获取的方式不对吗?不对,其实我们还需要进行一项配置:
运行结果:
可以看到我们的组件确实注册到Spring中了,剩下的是一些Spring内置的组件,我们无需关系。
context:component-scan 标签是用来进行组件扫描的,其中base-package属性用于配置需要扫描的包,一般情况下我们会扫描项目的顶包,即:最外层的包,这样所有项目中的组件都会被扫描到并注册。
事实上,@Component、@Controller、@Service、@Repository四个注解的作用是完全一样的,你也可以在组件上随意地使用它们,比如:
这是完全没有问题的,因为@Service、@Controller、@Repository注解是由@Component注解衍生出来的,但为了规范,还是建议将注解添加到指定的组件上。
自动注入
还记得Spring中的属性注入吗?如果不记得的话,我们来回顾一下:
若是想将一个对象属性注入进去,我们需要进行配置:
但Spring提供了一种更加便捷的注入方式, 自动注入 :
只需在User类的对象属性上添加@Autowired注解即可将Pet对象自动注入进来,而且它非常智能,我们对程序进行一些改造,首先去掉Pet类的@Component注解:
然后添加一个Dog类继承Pet,并注册:
来测试一下:
运行结果:
这样Dog类就被自动注入到User中了,但如果我们又创建了一个类继承Pet并注册:
此时程序就会报错:
这是Spring中比较常见的一个异常,意思是期望单个匹配的Bean:Pet,但是匹配到了两个Bean:cat、dog。错误非常好理解,因为Pet的子类有两个,所以Spring也不清楚我们到底想要哪一个Bean,所以抛出了异常。
这一问题会在Service层中出现,比如:
现在我们有一个UserService接口,并且有两个实现类,当自动注入UserService时显然会报错,那么如何解决这一问题呢?我们可以使用@Qualifier注解:
该注解的值即为需要注入的组件名,如果没有配置组件名,则默认是类名且首字母小写,当然了,我们也可以进行配置:
注入方式如下:
这一问题也可以使用@Primary注解解决:
当出现多个类型相同的类导致Spring无法选择时,如果某个类标注了@Primary,Spring将优先将该组件注册到IOC容器,不过这种方式确实不太优雅。
@Resource注解
刚才的问题其实可以通过换一个注解来解决,我们不妨试试看:
@Resource注解是JSR-250定义的注解,它和Spring没有关系,但能够实现和@Autowired注解相同的功能,我们先来介绍一下这两个注解之间的区别:
•@Autowired默认按类型进行注入,若要按名称注入,则需要配合@Qualifier注解一起使用;@Resource既支持类型注入,也支持名称注入,默认为名称注入•@Autowired能够标注在构造器、方法、参数、成员变量、注解上;@Resource只能标注在类、成员变量和方法上•@Autowired是Spring提供的注解,脱离了Spring框架则无法使用;@Resource是JSR-250定义的注解,可以脱离任何框架使用
现在问题就解决了吗?其实并没有,当你运行测试代码时程序仍然会抛出异常,这是因为虽然@Resource默认为名称注入,但是在使用名称找不到组件的情况下,会继续使用类型注入,所以眼熟的异常就又出现了。
我们已经知道,Spring在扫描组件时会将类名且首字母小写作为组件的名称注入到IOC容器中,所以像这样注入就是没有问题的:
不过一般情况下我们不会这么写,而是像这样:
通过@Resource注解,我们就解决了@Autowired和@Qualifier两个注解组合才能解决的问题,至于到底用哪个,还是看大家的使用习惯了。
@Value
可能有同学有疑问了,我知道对象类型的属性如何注入了,那基本类型数据如何注入呢?@Value注解能够帮助到你,使用方法如下:
不过一般情况下,我们都不会把数据这样写死,都会将其放到配置文件中:
此时需要借助一个新注解@PropertySource将值注入到指定的组件中:
@Value还能够注入操作系统属性:
还可以注入表达式计算后的结果:
Spring 注入 Bean 的 7 种方式,还有谁不会?
我们谈到Spring的时候一定会提到IOC容器、DI依赖注入,Spring通过将一个个类标注为Bean的方法注入到IOC容器中,达到了控制反转的效果。那么我们刚开始接触Bean的时候,一定是使用xml文件,一个一个的注入,就例如下面这样。
我们的项目一般很大的话,就需要成千上百个Bean去使用,这样写起来就很繁琐。那么Spring就帮我们实现了一种通过注解来实现注入的方法。只需要在你需要注入的类前面加上相应的注解,Spring就会帮助我们扫描到他们去实现注入。
xml扫描包的方式
一般情况下,注入Bean有一个最直白,最易懂的方式去实现注入,下面废话先不多说,先贴代码。
另外,Spring 系列面试题和答案全部整理好了,微信搜索Java面试库小程序,可以在线刷题。
Bean类
Configuration类
Test类
与xml有一点不同,这里在Test中,实例化的不再是 ClassPathXmlApplicationContext ,而是获取的 AnnotationConfigApplicationContext 实例。
上面的代码中MyBean也就是我们需要Spring去管理的一个Bean,他只是一个简单的类。而MyConfiguration中,我们首先用 @Configuration 注解去标记了该类,这样标明该类是一个Spring的一个配置类,在加载配置的时候会去加载他。
在MyConfiguration中我们可以看到有一个方法返回的是一个MyBean的实例,并且该方法上标注着 @Bean 的注解,标明这是一个注入Bean的方法,会将下面的返回的Bean注入IOC。
推荐一个 Spring Boot 基础教程及实战示例:
我们在生成一个Bean实例的时候,可以使用Bean的构造方法将Bean实现注入。直接看代码
Bean类
AnotherBean类
Configuration类
这里我们可以发现,和一般方式注入的代码不一样了,我们来看看新的注解都是什么意思:
@AutoWired
简单粗暴,直接翻译过来的意思就是自动装配:wrench:,还不理解为什么叫自动装配:wrench:?看了下一个注解的解释你就知道了。若是在这里注入的时候指定一个Bean的id就要使用 @Qualifier 注解。
@Component(默认单例模式)
什么??这翻译过来是零件,怎么感觉像是修 汽车 ??是的,Spring管理Bean的方法就是修 汽车 的方式。我们在需要将一个类变成一个Bean被Spring可以注入的时候加上注解零件 @Conmonent ,那么我们就可以在加载Bean的时候把他像零件一样装配:wrench:到这个IOC 汽车 上了
在这里我们还有几个其他的注解也可以实现这个功能,也就是细化的 @Component :
@ComponentScan("")
还是翻译,零件扫描,我们去看看括号里的“零件仓库”里面,哪些“零件”(类)需要被装载,Spring就会去扫描这个包,将里面所有标注了 @Component 的类进行注入。
这里的通过构造方法进行注入就很好理解了,我们在装配MyBean这个零件的时候,突然发现他必须在AnotherBean的基础上才能安装到IOC里面,那么我们就在每次装配MyBean的时候自动装配:wrench:一个AnotherBean进去。举个:chestnut:吧:
还是以 汽车 为例,我们在踩油门出发之前,是不是必须发车??这里的AutoWired的内容就像发车,你不发车,这个油门你踩断都没有用,他都不会走。
我们可以在一个属性的set方法中去将Bean实现注入,看代码吧
MyBean类
Configuration类 和 Test类
同上一个,就不贴了
这里我们发现在setter方法上我们有一个 @AutoWired ,与上面不同的是,我们不会在实例化该类时就自动装配:wrench:这个对象,而是在显式调用setter的时候去装配。
我们前面两种注入的方式诸如时间不同,并且代码较多,若是通过属性,即就是
这里我们可以看到我们这个类中需要使用AnotherBean这个实例对象,我们可以通过@AutoWired去自动装配它。
MyBeanList类
MyConfiguration类
这里我们将MyBeanList进行了注入,对List中的元素会逐一注入。
MyConfiguration类
注入与List中泛型一样的类型,会自动去匹配类型,及时这里没有任何List的感觉,只是String的类型,但他会去通过List的Bean的方式去注入。
同样这里也具有两种方式去注入Map类型Bean,且第二种的优先值高于第一种
以上就是Bean通过注解注入的几种方式,大家可以对比着xml注入的方式去看。