首页>>后端>>Spring->spring管理bean的方式(spring管理bean的方式工厂模式)

spring管理bean的方式(spring管理bean的方式工厂模式)

时间:2023-12-01 本站 点击:0

在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、2两种方法并不通用,可以抛弃了。

在配置文件中加入:

Xml代码

!-- 用于持有ApplicationContext,可以使用SpringContextHolder.getBean('xxxx')的静态方法得到spring bean对象 --

bean class="com.xxxxx.SpringContextHolder" lazy-init="false" /

Java代码

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

/**

* 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext.

*

*/

public class SpringContextHolder implements ApplicationContextAware {

private static ApplicationContext applicationContext;

/**

* 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.

*/

public void setApplicationContext(ApplicationContext applicationContext) {

SpringContextHolder.applicationContext = applicationContext; // NOSONAR

}

/**

* 取得存储在静态变量中的ApplicationContext.

*/

public static ApplicationContext getApplicationContext() {

checkApplicationContext();

return applicationContext;

}

/**

* 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.

*/

@SuppressWarnings("unchecked")

public static T T getBean(String name) {

checkApplicationContext();

return (T) applicationContext.getBean(name);

}

/**

* 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.

*/

@SuppressWarnings("unchecked")

public static T T getBean(ClassT clazz) {

checkApplicationContext();

return (T) applicationContext.getBeansOfType(clazz);

}

/**

* 清除applicationContext静态变量.

*/

public static void cleanApplicationContext() {

applicationContext = null;

}

private static void checkApplicationContext() {

if (applicationContext == null) {

throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");

}

}

}

spring配置bean实例化有哪些方式

1.实例化bean的三种方法:

(1) 构造器

!-- 体验1 --

bean id="personService" class="com.persia.PersonServiceBean"

!-- index 代表方法的参数序号,由0开始,基本的类型Type可以不声明--

constructor-arg index="0" value="构造注入的name" /

constructor-arg index="1" type="com.persia.IDaoBean" ref="personDao"/

/bean

对应类

public PersonServiceBean(String name, IDaoBean personDao) {

this.name = name;

this.personDao = personDao;

}

!-- 体现2--

bean id="personDao" class="cn.itcast.dao.impl.PersonDaoBean" /

bean id="personServiceBean" class="cn.itcast.service.impl.PersonServiceBean"

lazy-init="true" init-method="init" destroy-method="destory"

!-- ref属性对应id personDao值 name属性对应接口的getter方法名称--

property name="personDao" ref="personDao" /

!-- 体验3 --

!-- 注入属性值 --

property name="name" value="123"/

!-- Set的注入 --

property name="sets"

set

valuesets:第一个值/value

valuesets:第二个值/value

valuesets:第三个值/value

/set

/property

!-- List的注入 --

property name="lists"

list

valuelists:第一个值/value

valuelists:第二个值/value

valuelists:第三个值/value

/list

/property

!-- Properties的注入 --

property name="properties"

props

prop key="props-key1":第一个值/prop

prop key="props-key2":第二个值/prop

prop key="props-key3":第三个值/prop

/props

/property

!-- Map的注入 --

property name="maps"

map

entry key="maps-key1" value=":第一个值" /

entry key="maps-key2" value=":第二个值" /

entry key="maps-key3" value=":第三个值" /

/map

/property

/bean

(2) 静态工厂:

!-- 静态工厂获取bean --

bean id="personService2" class="com.persia.PersonServiceBeanFactory" factory-method="createInstance"/

对应类

public static PersonServiceBean createInstance(){

return new PersonServiceBean();

}

(3) 实例工厂:

没有静态方法,因此配置时,先实例化工厂,在实例化需要的bean。

!-- 实例工厂获取bean,先实例化工厂再实例化bean--

bean id="fac" class="com.persia.PersonServiceBeanInsFactory"/

bean id="personService3" factory-bean="fac" factory-method="createInstance"/

对应类

public PersonServiceBean createInstance(){

return new PersonServiceBean();

}

2. bean的作用域

默认情况为单例方式:scope=”singleton”

singleton

单实例作用域,这是Spring容器默认的作用域,使用singleton作用域生成的是单实例,在整个Bean容器中仅保留一个实例对象供所有调用者共享引用。单例模式对于那些无会话状态的Bean(如辅助工具类、DAO组件、业务逻辑组件等)是最理想的选择。

prototype

原型模式,这是多实例作用域,针对每次不同的请求,Bean容器均会生成一个全新的Bean实例以供调用者使用。prototype作用域非常适用于那些需要保持会话状态的Bean实例,有一点值得注意的就是,Spring不能对一个prototype

Bean的整个生命周期负责,容器在初始化、装配好一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。因此,客户端要负责prototype实例的生命周期管理。

request

针对每次HTTP请求,Spring容器会根据Bean的定义创建一个全新的Bean实例,

且该Bean实例仅在当前HTTP request内有效,因此可以根据需要放心地更改所建实例的内部状态,

而其他请求中根据Bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。

当处理请求结束,request作用域的Bean实例将被销毁。该作用域仅在基于web的Spring

ApplicationContext情形下有效。

session

针对某个HTTP

Session,Spring容器会根据Bean定义创建一个全新的Bean实例,且该Bean实例仅在当前HTTP Session内有效。

与request作用域一样,我们可以根据需要放心地更改所创建实例的内部状态,而别的HTTP Session中根据Bean定义创建的实例,

将不会看到这些特定于某个HTTP Session的状态变化。 当HTTP Session最终被废弃的时候,在该HTTP

Session作用域内的Bean实例也会被废弃掉。该作用域仅在基于Web的Spring ApplicationContext情形下有效。

global session

global

session作用域类似于标准的HTTP

Session作用域,不过它仅仅在基于portlet的Web应用中才有意义。portlet规范定义了全局Session的概念,它被所有构成某个portlet

Web应用的各种不同的portlet所共享。在global session作用域中定义的Bean被限定于全局portlet

Session的生命周期范围内。如果我们是在编写一个标准的基于Servlet的Web应用,并且定义了一个或多个具有global

session作用域的Bean,系统会使用标准的HTTP Session作用域,并且不会引起任何错误。该作用域仅在基于Web的Spring

ApplicationContext情形下有效。

3. bean的生命周期

(1)什么时候实例化?

对于单例的形式,在容器实例化的时候对bean进行实例化的。

ApplicationContext ctx=new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});

单实例可以通过lazy-init=”true”,在getBean时进行实例化。

在beans里面default-lazy-init=”true”对所有bean进行延迟处理。

对于prototype,则是在getBean的时候被实例化的。

(2)在bean被实例化之后执行资源操作等方法:

Init-method=””

(3)在bean销毁之前执行的方法:

Destroy-method=””

什么时候被销毁?随着spring容器被关闭时被销毁。

调用spring容器的close方法来正常关闭。以前是随着应用程序执行完而关闭。

在Spring装载配置文件后,Spring工厂实例化完成,开始处理

(1)使用默认构造方法或指定构造参数进行Bean实例化。

(2)根据property标签的配置调用Bean实例中的相关set方法完成属性的赋值。

(3)如果Bean实现了BeanNameAware接口,则调用setBeanName()方法传入当前Bean的ID。

(4)如果Bean实现了BeanFactoryAware接口,则调用setBeanFactory()方法传入当前工厂实例的引用。

(5)如果Bean实现了ApplicationContextAware接口,则调用setApplicationContext()方法传入当前ApplicationContext实例的引用。

(6)如果有BeanPostProcessor与当前Bean关联,则与之关联的对象的postProcess- BeforeInitialzation()方法将被调用。

(7)如果在配置文件中配置Bean时设置了init-method属性,则调用该属性指定的初始化方法。

(8)如果有BeanPostProcessor与当前Bean关联,则与之关联的对象的postProcess- AfterInitialzation()方法将被调用。

(9)Bean实例化完成,处于待用状态,可以被正常使用了。

(10)当Spring容器关闭时,如果Bean实现了DisposableBean接口,则destroy()方法将被调用。

(11)如果在配置文件中配置Bean时设置了destroy-method属性,则调用该属性指定的方法进行销毁前的一些处理。

(12)Bean实例被正常销毁。

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/5953.html