Spring不用注入获取bean,这样获取applicationContext.getBean()有什么好处吗

Spring不用注入获取bean,这样获取applicationContext.getBean()有什么好处吗,第1张

我接触spring自动注入的时间并不长,依稀记得有一点,一个类里可以使用自动注入其他bean的前提是这个类本身的管理也是要交给spring容器的。你调用这个方法所在的类可能并不是由spring来管理的,也就是说采用@Autowired这种自动注入应该是无效的,在针对这种情形,spring确实提供这样一种途径,就是在无法自动注入的情况下,直接调用beanfactory去拿某个bean的实例,调用这样方法得到的实例是跟自动注入得到的实例是一样的。

但是如果你主动去new这样一个bean,那spring容器是不会帮助你把这个bean里的属性初始化好的。

如果可以直接自动注入,谁不想省事一点呢,以上基本是我个人一点浅薄的项目经验,希望对你有帮助。

使用Spring MVC,配置DispatcherServlet是第一步。

DispatcherServlet是一个Servlet,所以可以配置多个DispatcherServlet。

DispatcherServlet是前置控制器,配置在webxml文件中的。拦截匹配的请求,Servlet拦截匹配规则要自已定义,把拦截下来的请求,依据某某规则分发到目标Controller(我们写的Action)来处理。

“某某规则”:是根据你使用了哪个HandlerMapping接口的实现类的不同而不同。

先来看第一个例子:

Xml代码

<load-on-startup>1</load-on-startup>是启动顺序,让这个Servlet随Servletp容器一起启动。

<url-pattern>form</url-pattern>会拦截form结尾的请求。

<servlet-name>example</servlet-name>这个Servlet的名字是example,可以有多个DispatcherServlet,是通过名字来区分的。每一个DispatcherServlet有自己的WebApplicationContext上下文对象。同时保存的ServletContext中和Request对象中,关于key,以后说明。

在DispatcherServlet的初始化过程中,框架会在web应用的WEB-INF文件夹下寻找名为[servlet-name]-servletxml的配置文件,生成文件中定义的bean。

ApplicationContext是Spring中的重要组件,它不是bean,因此无法通过getBean获取它,但是可以通过Autowired注入获得,其中必定有特殊的处理,本文将简述ApplicationContext及类似的BeanFactory是如何实现注入逻辑的最后稍微介绍一下Aware接口

普通Bean依赖Spring的容器功能进行注入,而ApplicationContext通过Spring的内建机制进行注入

查找依赖时 ,会同时搜寻beanDefinitionNames和resolvableDependencies,因此ApplicationContext也能被查找到

getBean时 只会查找上面的BeanDefinitionMap,因此找不到ApplicationContext

在AbstractApplicationContextprepareBeanFactory()中,ApplicationContext被注册到resolvableDependencies中

创建SimpleBean3时,Spring检测到有applicationContext和simpleBean2两个依赖,便会进行查找

在 SpringBoot中@Autowired是如何生效的 那篇文章中,讲到了带有@Autowired字段的在AutowiredAnnotationPostProcessorpostProcessProperties()中完成注入,查找依赖的入口就在 metadatainject(bean, beanName, pvs)

和注入相关的流程如下

我们直接跳到DefaultListableBeanFactoryfindAutowireCandidates(),可以看到是同时从BeanDefinitionNames和resolvableDependencies两个地方,因此可以找到ApplicationContext

Aware是一个标记接口,要求子接口需要提供一个回调setter方法使用者可以在恰当的时机被回调,举个例子,实现了ApplicationContextAware的实例会在某个时间触发setApplicationContext获得applicationContext的实例

那么直接@Autowired注入和使用ApplicationContextAware注入有什么区别呢

ApplicationContext不是bean,不能通过bean的方式进行注入,为了方面使用Spring通过特殊方式满足用户的注入需求,同时又提供了Aware系列接口,给与用户更大的自由度

  Spring容器提供了一种管理方法,致力于解决我们各个层级之间的对象的调用关系。

  我们通常调用各层级对象的时候,需要不断创建对象,一次访问就需要创建两个对象;如果我们使用Spring容器,将不同层级的对象放入容器中,每次使用的时候调用容器中的对象,就不用创建那么多对象,达到节约内存空间的目的。简单来讲,Spring容器就是存储JavaBean对象的容器。

  BeanFactory是一个接口,需要创建继承的子类对象。下图是其继承结构图:

方式二:使用ClassPathApplicationContext获取容器类

  这个方法替代了方式一,是我们创建容器类对象主要使用的方法。

方式三:使用FileSystemXmlApplicationContext来获取容器对象

  这种方式在创建对象的时候需要传入配置文件的绝对路径,这个方法可以使用项目外部的配置文件

  IOC(inversion of controller)指的是控制反转,简单来书,就是讲创建对象的过程或者创建对象的权限交给了spring框架来帮我们处理,我们不用再通过new的方式来创建JavaBean对象,这个过程就叫做IOC。

首先在applicationContext中配置我们的对象

然后从容器中获取我们的JavaBean对象

创建bean的工厂类

在配置文件中进行配置

获取JavaBean对象

创建工厂类的方式与上面相同

在配置文件中进行配置

获取JavaBean对象

Bean属性scope可以声明bean的作用域范围,Bean的作用域范围有四种:

我们可以在JavaBean类中添加init-method与destroy-method两个方法,实现bean在初始化和关闭的时候调用的方法,然后在配置文件中进行配置。

JavaBean类

配置文件

  DI(dependency injection)指的是依赖注入,简单来说就是使用spring框架对我们的JavaBean对象赋值的过程。

使用上文中创建的JavaBean类

注意:一定要给属性生成对应的setter方法

配置JavaBean类的属性

从容器中获取我们的JavaBean对象

在JavaBean中生成带所有属性的构造方法

在配置文件中申明JavaBean对象

申明的另一种方法:

调用JavaBean的属性

  P名称空间与C名称空间其实都是不存在的虚拟空间,主要是用于简化我们的spring为JavaBean属性赋值时的配置。

添加P名称空间与C名称空间到schema

通过setter方法进行赋值:

等价于:

通过构造方法进行赋值

等价于:

  Spel表达式,类似于jstl与el表达式的语言,spring可以支持我们在为属性赋值的时候,通过spel表达式来进行更改我们的属性值。

创建一个含有集合属性的JavaBean类

为集合属性注入值

如果说BeanFactory是spring的心脏,那么Application就是完整的身躯。ApplicationContext就是由BeanFactory派生出来的。

1、ApplicationContext

ApplicationContext的主要实现类是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,前者默认从类路径加载配置文件,后者默认从文件系统加载文件。

如果配置文件放在类路径下,直接使用ClassPathXmlApplicationContext实现类:

ApplicationContext ctx=new ClassPathXmlApplicationContext("com/techman/context/beansxml");

这里的参数等同于:"classpath:com/techman/context/beansxml"

如果配置文件在文件系统的路径下,则可以优先考虑使用FileSystemXmlApplicationContext实现类:

ApplicationContext ctx=new FileSystemXmlApplicationContext("com/techman/context/beansxml");

这里的参数等同于:"file:com/techman/context/beansxml"

还可以指定一组配置文件,Spring自动将多个配置文件在内存中整合成一个配置文件:

ApplicationContext ctx=new ClassPathXmlApplicationContext(new String[]{"conf/bean1xml","conf/bean2xml"});

2、AnnotationConfigApplicationContext

直接实例:

[java] view plaincopyprint

package comtechmancontext;

import orgspringframeworkcontextannotationBean;

import orgspringframeworkcontextannotationConfiguration;

import comtechmanreflectCar;

@Configuration //表示是一个配置信息提供类,这里是通过类注解的配置方式

public class Beans

{

@Bean(name="car")

public Car buildCar()

{

Car car=new Car();

carsetBrand("红旗CA72");

carsetMaxSpeed(340);

return car;

}

}

复制代码

[java] view plaincopyprint

package comtechmancontext;

import orgspringframeworkcontextApplicationContext;

import orgspringframeworkcontextannotationAnnotationConfigApplicationContext;

import comtechmanreflectCar;

//这里需要spring-contextjar和spring-expressionjar的支持

public class AnnotationApplicationContext

{

public static void main(String []args)

{

//通过一个带@Configuration的POJO装载Bean配置

ApplicationContext ac=new AnnotationConfigApplicationContext(Beansclass);

Car car=acgetBean("car",Carclass);

carintroduce();

}

}

复制代码

AnnotationConfigApplicationContext将加载Beansclass中的Bean定义并调用Beansclass中实现的方法实例化Bean,启动容器并装配Bean

3、WebApplicationContext

WebApplicationContext是专门为Web应用准备的,它允许从相对于web根目录的路径中加载配置文件完成初始化工作。

WebApplicationContext扩展了ApplicationContext,WebApplicationContext定义了一个常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文启动时,我们可以直接通过下面的语句从web容器中获取WebApplicationContext:

WebApplicationContext wac=(WebApplicationContext)servletContextgetAttribute(WebApplicationContextROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

4、ConfigurableWebApplicationContext

ConfigurableWebApplicationContext扩展了WebApplicationContext,它允许通过配置的方式实例化WebApplicationContext,它定义了两个重要的方法:

setServletContext(ServletContext servletContext):为Spring设置Web应用上下文,以便两者整合。

setConfigLocation(String[] configLocations)设置Spring配置文件地址,一般情况下,配置文件地址是相对于Web根目录的地址,如/WEB-INF/techman-daoxml等。也可以使用classpath:com/techman/context/techman-daoxml等格式。

5、Spring为使用WebApplicationContext的Servlet和Web容器监听器:

orgspringframeworkwebcontextContextLoaderServlet;

orgspringframeworkwebcontextContextLoaderListener;

这里是webxml启动WebApplicationContext的配置:

[html] view plaincopyprint

<!-- 从类路径下加载Spring配置文件,classpath关键字特指类路径下加载 ,如果多个文件则使用逗号或空格隔开-->

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:applicationContextxml,/WEB-INF/techman-daoxml</param-value>

</context-param>

<!-- 负责启动Spring容器的监听器,它将引用上面的上下文参数获得Spring配置文件地址 -->

<listener>

<listener-class>orgspringframeworkwebcontextContextLoaderListener</listener-class>

</listener>

复制代码

如果在不支持容器监听器的低版本Web容器中,我们可采用ContextLoaderServlet完成相同的工作:

[html] view plaincopyprint

<!-- 从类路径下加载Spring配置文件,classpath关键字特指类路径下加载 ,如果多个文件则使用逗号或空格隔开-->

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:applicationContextxml,/WEB-INF/techman-daoxml</param-value>

</context-param>

复制代码

[html] view plaincopyprint

<servlet>

<servlet-name>springContextLoaderServlet</servlet-name>

<servlet-class>orgspringframeworkwebcontextContextLoaderServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

复制代码

6、Log4j的配置

由于WebApplicationContext需要使用日志功能,用户可以将log4jproperties放置在类路径下,这样就会自动启动。如果放在其他地方,必须在webxml中指定Log4j配置文件的位置。Spring为启动Log4j引擎提供了两个类og4jConfigServlet和Log4jConfigListener,不管哪种方式都必须保证能够在装载Spring配置文件前先装载Log4J配置信息。

[html] view plaincopyprint

<context-param>

<param-name>log4jConfigLocation</param-name>

<param-value>/WEB-INF/log4jproperties</param-value>

</context-param>

<servlet>

<servlet-name>log4jConfigServlet</servlet-name>

<servlet-class>orgspringframeworkwebutilLog4jConfigServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

复制代码

7、使用标注@Configuration的Java类提供配置信息

方式如下:

[html] view plaincopyprint

<!-- 通过指定context参数,让Spring使用AnnotationConfigWebApplicationContext而非XmlWebApplicationContext启动容器 -->

<context-param>

<param-name>contextClass</param-name>

<param-value>

orgspringframeworkwebcontextsupportAnnotationConfigWebApplicationContext

</param-value>

</context-param>

<!-- 指定标注了@Configuration的配置类,多个可以使用逗号或空格分隔 -->

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>comsmartBeans,comsmartAppConfig2</param-value>

</context-param>

<!-- ContextLoaderListener监听器将根据上面的配置使用AnnotationConfigWebApplicationContext根据contextConfigLocation指定的配置类启动Spring容器 -->

<listener>

<listener-class>orgspringframeworkwebcontextContextLoaderListener</listener-class>

</listener>

众所周知,Context的含义是上下文,也就是场景的意思,关于获取全局Context的方法,一般情况是在自定义的Application中写一个,需要的时候直接获取就可以了,下面是代码所示: 

private static Context context; 

private static Context getContext(){ 

return context; 

@Override 

public void onCreate() { 

superonCreate(); 

context=thisgetApplicationContext(); 

thisregisterActivityLifecycleCallbacks(this); 

上面的代码是写在自定义的Application中的,以后我们需要获取全局Context的时候就用BaseApplicationgetContext()方法即可,请注意,上面的方法只是一般情况下的,就是我们已经进入了这个程序里面,但是就像刚才说的那样,如果不能接触程序逻辑,或者连Application都没有初始化的时候能获取吗,显然不能吧?那是不是就没有办法了?不是滴,经过查看源码,我们发现应用程序的入口里面就提供了获取全部Application的方法,这个类是ActivityThread,这个类也是大名鼎鼎的Android应用程序的主线程,它里面做的事情可多了呢,包括初始化消息循环机制等等,这也是为什么在主线程里面可以直接new

一个Handler的原因,而不用绑定线程的Looper,当然,本文讨论的问题不是Looper,而是全局Context对象,我们发现,ActivityThread有一个方法: 

public Application getApplication() { 

return mInitialApplication; 

利用这个方法我们可以获取全局Application对象,当然也就可以获取全局Context对象啦,可问题是ActivityThread是一个隐藏类,怎么办呢,那就反射吧,下面是代码

Class<> clazz = ClassforName("androidappActivityThread");

Field field = clazzgetDeclaredField("sCurrentActivityThread");

fieldsetAccessible(true);

//得到ActivityThread的对象,虽然是隐藏的,但已经指向了内存的堆地址

Object object = fieldget(null);

Logd("[app]", "object=" + object);

Method method=clazzgetDeclaredMethod("getApplication");

methodsetAccessible(true);

Application application=(Application)methodinvoke(object);

Logd("[app]","application="+application);

Logd("[app]","程序的application对象="+getApplication());

测试结果如下:

可以看到成功获取了Application对象,那么获取Context就容易啦,而且我们看到,这样反射获取的跟直接程序调用的结果是一样的,其实这也很好理解,总之,这种方法一般情况下是在特殊的时候使用,比如注入的 *** 作可能使用到,好了,今天的博文就写到这里,有什么疑问提出来,其实ActivityThread还有一个静态方法直接获取application,获取的结果也是这个,都是一样的,大家去试试吧。需要补充的是,这个方法是无敌的,就像标题所说,任何地方,任何时候,任何逻辑,只要程序进入了主线程就能获取,而不是仅仅局限于网上说的在自定义的application中获取

以上就是关于Spring不用注入获取bean,这样获取applicationContext.getBean()有什么好处吗全部的内容,包括:Spring不用注入获取bean,这样获取applicationContext.getBean()有什么好处吗、dispatcherservlet怎么获取webapplicationcontext、ApplicationContext是如何被注入的等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9455143.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-28
下一篇2023-04-28

发表评论

登录后才能评论

评论列表(0条)

    保存