java中的mapper是什么Spring是什么?

SpringMVC和Spring是什么关系? - 知乎119被浏览48435分享邀请回答8添加评论分享收藏感谢收起13添加评论分享收藏感谢收起查看更多回答14507人阅读
从前年开始使用spring和hibernate,mybatis等框架时,就转到注解来了。直到前些时,突然对注解开始好奇起来。为什么写注解就可以了?不需要大量配置文件呢?于是我查看了一些资料,对注解有了初步了解。
引言:什么是注解?
在IDE中,我们可以链接spring mvc中的@RequestMapping注解,发现以下源码
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
public String[] value() default {};
public RequestMethod[] method() default {};
public String[] params() default {};
public String[] headers() default {};
public String[] consumes() default {};
public String[] produces() default {};
}这其实就是注解的写法。从这里我们可以发现,注解的写法比较简单,只要在intface前面加上@,就可以定义一个注解。但有几个其他的注解我们还不是很明白,同样spring是怎么通过这个注解进行运转的呢?
首先:注解的作用是什么?
1》生成文档,比如我们用的ide里面会自动加上比如@param,@return,@author等注解。
2》编译时格式检查。这个最常见的是@override,@SuppressWarnings等等。
3》跟踪代码依赖性,实现替代配置文件功能。上面的源码例子其实就是这个作用。
其次:元注解
在包 java.lang.annotation 中包含所有定义【自定义注解】所需用到的原注解和接口。如接口 java.lang.annotation.Annotation 是所有注解继承的接口,并且是自动继承,不需要定义时指定,类似于所有类都自动继承Object。查看Documented.class,可以看到这是个借口。它有三个注解(@Documented,@Retention,@Target),除此外,还有@Inherited,构成4个元注解。
@Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。
在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。
@Retention 表示在什么级别保存该注解信息。可选的参数值在枚举类型 RetentionPolicy 中,包括:&
& & & & & RetentionPolicy.SOURCE 注解将被编译器丢弃&
& & & & & RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃&
& & & & & RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。
@Target 表示该注解用于什么地方,可能的值在枚举类 ElemenetType 中,包括:&
& & & & & ElemenetType.CONSTRUCTOR 构造器声明&
& & & & & ElemenetType.FIELD 域声明(包括 enum 实例)&
& & & & & ElemenetType.LOCAL_VARIABLE 局部变量声明
& & & & & ElemenetType.ANNOTATION_TYPE 作用于注解量声明
& & & & & ElemenetType.METHOD 方法声明
& & & & & ElemenetType.PACKAGE 包声明&
& & & & & ElemenetType.PARAMETER 参数声明&
& & & & & ElemenetType.TYPE 类,接口(包括注解类型)或enum声明&
@Inherited 允许子类继承父类中的注解。
然后:我们来自己编写注解
* 自定义注解
* @author Fly
@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest {
public String name() default &&;
public String sex() default &男&;
&* 注解测试
&* @author Fly
@AnnotationTest(sex = &男&, name = &张飞&)
public class MyAnnotationTest {
& & @AnnotationTest(sex = &男&, name = &Fly&)
& & public void setFly() {
& & @AnnotationTest(sex = &女&, name = &李明&)
& & public void setLiMing() {
& & public static void main(String[] args) {
& & & & //检查类MyAnnotationTest是否含有@AnnotationTest注解
& & & & if (MyAnnotationTest.class.isAnnotationPresent(AnnotationTest.class)) {
& & & & & & //若存在就获取注解
& & & & & & AnnotationTest annotation = (AnnotationTest) MyAnnotationTest.class.getAnnotation(AnnotationTest.class);
& & & & & & System.out.println(annotation);
& & & & & & //获取注解属性
& & & & & & System.out.println(annotation.sex());
& & & & & & System.out.println(annotation.name());
& & & & & & System.out.println(&///////////////////////////////////////////&);
& & & & & & Method[] _methods = MyAnnotationTest.class.getDeclaredMethods();
& & & & & & for (Method method : _methods) {
& & & & & & & & System.out.println(method);
& & & & & & & & if (method.isAnnotationPresent(AnnotationTest.class)) {
& & & & & & & & & & AnnotationTest test = method.getAnnotation(AnnotationTest.class);
& & & & & & & & & & System.out.println(&AnnotationTest(method=& + method.getName() + &,name=& + test.name() + &,sex=& + test.sex() + &)&);
& & & & & & & & }
& & & & & & }
}测试结果如下:
@test.AnnotationTest(sex=男, name=张飞)
///////////////////////////////////////////
public static void test.MyAnnotationTest.main(java.lang.String[])
public void test.MyAnnotationTest.setLiMing()
AnnotationTest(method=setLiMing,name=李明,sex=女)
public void test.MyAnnotationTest.setFly()
AnnotationTest(method=setFly,name=Fly,sex=男)
到这里,我们对注解的基本有点了解了,注解的运用其实与反射式分不开的。我们可以利用代码中的注解间接控制程序代码的运行,它们通过Java反射机制读取注解的信息,并根据这些信息更改目标程序的逻辑。但是我们怎么使用注解呢?怎么让注解发挥作用,例如spring等框架时如何应用注解的呢?
然后:注解理解的深入
我们结合spring的控制反转和依赖注入来继续说明这个问题。
看下面的代码,首先是一个IUser接口,包含一个login方法。然后又一个中文登录方法和英文登录方法都实现了Iuser接口。
public interface IUser {
public void login();
public class ChineseUserImpl implements IUser {
public void login() {
System.err.println(&用户登录!&);
}public class EnglishUserImpl implements IUser {
public void login() {
System.err.println(&User Login!&);
}然后有一个Test类,要注入IUser接口
@AnnotationTest
public class Test {
private IU
public IUser getUserdao() {
@AnnotationTest(nation = &ChineseUserImpl&)
public void setUserdao(IUser userdao) {
this.userdao =
public void loginTest() {
userdao.login();
}我们实现的是setter注入方式。为了配合这个例子,我把@AnnotationTest也稍作修改。
@Documented
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest {
public String nation() default &&;
}然后再引入一个类Container,类似spring容器的作用
public class Container {
public static Test getBean() {
Test test = new Test();
if (Test.class.isAnnotationPresent(AnnotationTest.class)) {
Method[] methods = Test.class.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
if (method.isAnnotationPresent(AnnotationTest.class)) {
AnnotationTest annotest = method.getAnnotation(AnnotationTest.class);
System.out.println(&AnnotationTest(field=& + method.getName()
+ &,nation=& + annotest.nation() + &)&);
userdao = (IUser) Class.forName(&test.& + annotest.nation()).newInstance();
test.setUserdao(userdao);
} catch (Exception ex) {
Logger.getLogger(Container.class.getName()).log(Level.SEVERE, null, ex);
System.out.println(&没有注解标记!&);
}在容器里面我使用反射获取注解属性nation所标注的内容,然后对Test类中的接口进行具体实现。这里的Container就是所谓的外部容器,可以对我们的注解或者是xml配置文件进行解析,以降低耦合性。
最后我们再进行测试,代码如下
* 注解测试
* @author Fly
public class MyAnnotationTest {
public static void main(String[] args) {
Test test = Container.getBean();
test.loginTest();
}测试结果如下:
public void test.Test.loginTest()
public void test.Test.setUserdao(test.IUser)
AnnotationTest(field=setUserdao,nation=ChineseUserDaoImpl)
public test.IUser test.Test.getUserdao()
用户登录!如果我把Test类中的@AnnotationTest(nation = &ChineseUserImpl&)
@AnnotationTest(nation = &EnglishUserImpl&)结构就变成
public void test.Test.loginTest()
public test.IUser test.Test.getUserdao()
public void test.Test.setUserdao(test.IUser)
AnnotationTest(field=setUserdao,nation=EnglishUserImpl)
User Login!
1、所有的注解类都隐式继承于 java.lang.annotation.Annotation,注解不允许显式继承于其他的接口。
2、注解不能直接干扰程序代码的运行,无论增加或删除注解,代码都能够正常运行。Java语言解释器会忽略这些注解,而由第三方工具负责对注解进行处理。
3、一个注解可以拥有多个成员,成员声明和接口方法声明类似,这里,我们仅定义了一个成员,成员的声明有以下几点限制:
a) & 成员以无入参无抛出异常的方式声明,如boolean value(String str)、boolean value() throws Exception等方式是非法的;
b) & 可以通过default为成员指定一个默认值,如String level() default &LOW_LEVEL&、int high() default 2是合法的,当然也可以不指定默认值;
c) & 成员类型是受限的,合法的类型包括原始类型及其封装类、String、Class、enums、注解类型,以及上述类型的数组类型。如ForumService value()、List foo()是非法的。
d) & 如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略成员名和赋值号(=),如@Description(&使用注解的实例&)。注解类拥有多个成员时,如果仅对value成员进行赋值则也可不使用赋值号,如果同时对多个成员进行赋值,则必须使用赋值号,如@DeclareParents (value = &NaiveWaiter&, defaultImpl = SmartSeller.class)。
e) & 注解类可以没有成员,没有成员的注解称为标识注解,解释程序以标识注解存在与否进行相应的处理;
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:173274次
积分:2215
积分:2215
排名:第17056名
原创:62篇
转载:13篇
评论:61条
(1)(1)(2)(2)(7)(3)(1)(2)(1)(3)(1)(1)(1)(2)(3)(2)(2)(3)(1)(2)(1)(3)(2)(1)(1)(2)(7)(3)(2)(1)(6)(5)解析Java的Spring框架的基本结构
作者:liweisnake
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了Java的Spring框架的基本结构,作者从Spring的设计角度触发解析其基础的架构内容,需要的朋友可以参考下
&& 在java届,有位名叫Rod Johnson的牛人,发现最初的java企业级开发处于混沌状态。
&& 于是,它决心编写一个能够解决问题的通用的基础架构。
&& 因为它深信面向接口编程能够将变化控制到最小,同时也利于扩展和变化。于是,它编写了如下的接口。&
&& 在混沌状态最先要创造的是一切对象的母亲BeanFactory,有了它,就能够得到一切它孕育的对象和属性,也就是说首先要造盖亚--大地之母。
&& 有了最初的母亲BeanFactory,johnson想,如果我要得到一组Bean对象而不单单是某个或某几个呢?另外,如果母亲的孩子也要孕育对象呢?于是,johnson创造了ListableBeanFactory以操作一组bean对象,比如getBeansOfType就能够根据得到同类型的一组Bean;创造了HierarchicalBeanFactory来解决多个BeanFactory的层次问题,比如getParentBeanFactory就能够得到BeanFactory的父Factory。
&& 这个BeanFactory最终是要在某个应用上使用的,那么,需要给予BeanFactory在一个应用中活动的能力。在BeanFactory中,只需要考虑跟bean相关的行为,比如怎么得到bean,bean的类型等;而如果要赋予其在应用中的能力,则就需要考虑更多,比如应用的名字,启动时间,id等等跟应用本身相关的行为和属性,于是johnson想到了创造ApplicationContext。johnson想,这个ApplicationContext一定要能做许多事,要能够处理参数化和国际化的文本信息,于是增加了MessageSource接口;要能发布事件以便解耦组件,于是有了ApplicationEventPublisher接口;要能得到资源文件,于是有了ResourcePatternResolver接口;要能有在不同环境有不同处理对象的能力,于是有了EnvironmentCapable接口。
&& ApplicationContext继承了所有这些接口。
&& 但是最重要的是,无论是BeanFactory还是ApplicationContext,它们都需要有可配置的能力,于是有了子接口ConfigurableBeanFactory和ConfigurableApplicationContext;另外,web在当时是非常重要的趋势,而且相比其他应用有些独特,需要得到ServletContext,于是有了WebApplicationContext。
&& 到目前为止,johnson都是面向接口进行行为的抽象思考,并未具体实现他们。
&& 看着创造出来的BeanFactory和ApplicationContext,johnson意识到这一天的工作远远没有结束,因为并没有真正解决怎么能够让整套体系运转起来,于是,johnson开始思索如何实现他们。
&& johoson首先想到的还是这个实现应该具备什么能力?当然要把之前提到的AutowireCapableBeanFactory,ListableBeanFactory和ConfigurableBeanFactory都包括进去。因此创造了ConfigurableListableBeanFactory。其次,需要考虑对于bean对象的几种能力,一是起别名的能力;二是保存单例对象的能力;三是缓存的能力;他们分别在SimpleAliasRegistry类,DefaultSingletonBeanRegistry类和FactoryBeanRegistrySupport类中实现。
&& 最终,创造出了DefaultListableBeanFactory,它是spring中一切ioc工厂的原型,是BeanFactory第一个真正的孩子,这个孩子非常重要,已经成为独立的创建ioc容器的基础,如果有扩展和使用,大多是继承它或者组合使用它。
& 如果要初始化一个DefaultListableBeanFactory,可以用如下代码
ClassPathResource res = new ClassPathResource("applicationContext.xml");
DefaultListableBeanFactory f = new DefaultListableBeanFactory();
XmlBeanDefinitionReader r = new XmlBeanDefinitionReader(f);
r.loadBeanDefinitions(res);
& 接下来johnson想,BeanFactory有了一个功能比较全面的默认实现,那么ApplicationContext呢?于是johnson孜孜不倦的创造了3个重要的ApplicationContext实现:FileSystemXmlApplicationContext, ClassPathXmlApplicationContext, AnnotationConfigWebApplicationContext(其实还有很多,比如处理portlet的, 处理web的)
&&& johnson最先考虑的是如何去做spring的启动流程,它应该放到一个比较抽象的层次以便下层的所有类能够复用。于是他用一个AbstractApplicationContext实现了ConfigurableApplicationContext。还有一个很重要的功能,即将一个文件以资源的形式加载进来,这需要将资源抽象为Resource类,将定位资源的具体实现抽象到ResourceLoader,AbstractApplicationContext同样需要继承DefaultResourceLoader以提供这个功能。AbstractApplicationContext完成了整个启动流程(上帝将它安排在第二天完成),唯独没有做对BeanFactory的管理。于是,它的子类AbstractRefreshableApplicationContext专门做了这件事,实现了refreshBeanFactory, closeBeanFactory, getBeanFactory专门对BeanFactory的生命周期做了一些管理,但是AbstractRefreshableApplicationContext仍然没有加载所有配置好的Bean。到哪里加载配置好的资源,实际上到了下层的子类去做,比如FileSystemXmlApplicationContext,就是到文件系统去读一个xml形式的applicationContext;ClassPathXmlApplicationContext则是到类加载路径下去读这个applicationContext。而AnnotationConfigWebApplicationContext则从类文件的annotation中加载bean,spring的扫描也从此开始。
& 看着主要的框架已经建立起来,johnson满意的笑着睡着了。
&& 头一日,johnson完成了一个spring的整体框架。
& 第二日,johnson准备实际去处理前面遗留的问题。比如spring的容器初始化过程。如图,johnson将这个过程分为很多子过程,这些子过程都在围绕着如何将bean载入这一宏伟的目标而努力。
&&& 这个过程放在AbstractApplicationContext中的refresh方法中。代码如下,johnson将refresh的过程分为很多子过程,并且这些子过程在同一个抽象层级上,这种写法是为了给后人一个榜样。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
& 如果更高层次一些看,实际上这些过程围绕着几个方面来做:1. 刷新的生命周期;2. 对beanFactory的初始化及准备;3. 生成并注册beanDefinition;4. beanFactory后处理器;5.设置消息,事件及监听器。
& 1. 刷新的生命周期
&&& prepareRefresh,这个过程主要记录日志表示spring启动了,初始化property资源(比如serlvet中一些资源初始化),以及property资源的验证(比如只写了key没有value)。
& onRefresh,目的是提供给一些特殊的ApplicationContext,使他们有能够在刷新过程中能够扩展的能力。目前使用到的大多是为servlet application context设置theme
& finishRefresh,做一些收尾的工作,如初始化LifecycleProcessor,发布refresh结束的事件等。
& cancelRefresh,主要是在异常产生时将当前的状态改变为非active。
& 2. 对beanFactory的初始化及准备
& johnson想,我们应该让beanFactory在初始化时就把bean透明的加载并注册好,这样对外界而言,我的封装就非常成功,因此这步实际上做了很多事。下图省略了许多步骤,只列出关键点。
& AbstractApplicationContext会调用refreshBeanFactory,它首先会检查并关闭已有的beanFactory,其次新建一个beanFactory,然后利用该factory装载所有BeanDefinition
& 其中,loadBeanDefinitions会交给子类做不同的实现,比如AbstractXmlApplicationContext主要是通过xml读取;AnnotationConfigWebApplicationContext的实现则会调用扫描器扫描类中的bean
&& 3. 生成并注册beanDefinition
& 当解析完xml配置以后,DefaultBeanDefinitionDocumentReader的parseDefaultElement方法会根据xml中的元素做对应的处理。其中,遇到bean元素时会最终调用BeanDefinitionReaderUtils中的registerBeanDefinition方法,该方法传入的参数为BeanDefinitionRegistry,实际上是回调了DefaultListableBeanFactory的registerBeanDefinition方法来注册beanDefinition(DefaultListableBeanFactory实现了BeanDefinitionRegistry)。
&& 4. beanFactory后处理器
&& beanFactory后处理器是spring提供出来的让其子类灵活扩展的方式。spring中分为2个步骤:postProcessBeanFactory,invokeBeanFactoryPostProcessors。registerBeanPostProcessors则是实例化并调用所有的BeanPostProcessor,用来在bean初始化前和初始化后对bean做扩展。
&& 5. 设置消息,事件及监听器
& 设置默认消息源为DelegatingMessageSource,如工厂里已经有messageSource则使用该messageSource,事件多播器为SimpleApplicationEventMulticaster,如工厂里已经有applicationEventMulticaster,则使用该applicationEventMulticaster,并注册所有的应用程序Listener以便能够接收事件
& 消息源:MessageSource是国际化资源文件的重要方法,spring在applicationContext就支持消息源。
& spring中提供了MessageSource的默认实现,使用java.util.ResourceBundle来提取消息。spring通过配置一个特殊id为messageSource的bean并制定i18n的文件名,就能够从ApplicationContext.getMessage()直接访问message。如果在jsp中,还能通过spring:message这个tag访问到message。
& 事件:事件是比较重要的解耦机制,spring在核心ApplicationContext就引入了它,其原理比较简单,一方面是事件产生方,能够发送事件;一方面似乎事件监听方,能够响应事件。而具体实现基本上都是在产生方hold住一个事件监听者集合,并将所有监听方“注册”(即加入)到这个事件监听者集合。
& spring中将ApplicationContext当做事件产生方,使用applicationListeners作为监听者集合,applicationEventMulticaster用来做事件发布。
& 事件发布的几个步骤:
& 订阅:最初addApplicationListener将applicationListener加入监听者集合。
& 发布:ApplicationContext继承了ApplicationEventPublisher,因而实现了publishEvent,该方法首先会遍历本applicationContext的applicationListeners集合,对每个listener调用onApplicationEvent,因此每个listener都会被通知到;这步完成后会对applicationContext的parent的所有applicationListeners做同样的事件发布。
& 事件发布非常常用,不仅我们自己的应用可以使用这个事件发布,spring框架自身也在使用事件发布。下面是一些spring中事件的应用:
& 在finishRefresh中会发布ContextRefreshedEvent表明refresh结束借此通知listener。在ApplicationContext中start和stop方法会发布事件表示context开始或结束。
& johnson将spring的主框架与运行流程创造完毕之后,发觉spring中提供了许多灵活扩展的地方。于是johnson准备在第三日将这些灵活扩展的用法公布出来。
& 1. BeanPostProcessor。BeanPostProcessor提供了bean创建完成后的扩展接口,当你需要在bean创建完后对其做一定处理,则BeanPostProcessor是首选的方式。
& 2. Aware。注入的bean需要了解其容器的某些部分,spring通过Aware完成回调,如BeanNameAware,可以让bean得知自己的名字, BeanFactoryAware可以让bean了解到BeanFactory, ApplicationContextAware,可以让bean操作ApplicationContext。通过这种方式,注入spring的bean能够做更加广泛的事情。
& 对于BeanPostProcessor的扩展,spring自身有一个例子,即如何识别Aware bean的例子。Aware bean是比较特殊的bean,需要spring对其额外注入一些属性,那么注入的过程spring会怎么做呢?实际上spring并没有将他写在核心的处理过程里面,而是放到了ApplicationContextAwareProcessor这个BeanPostProcessor,通过BeanPostProcessor的postProcessBeforeInitialization最终invokeAwareInterfaces以判断该bean的类型并注入相应的属性。这种做法利用了BeanPostProcessor完成了另一个扩展用法,实在是高超。
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
& 关于Aware的用法则更多了,比如如下代码能够感知ApplicationContext,spring在创建完这个bean之后便会注入ApplicationContext,于是我们就可以使用该context完成事件发布。
public class HelloBean implements ApplicationContextAware {
private ApplicationContext applicationC
private String helloWord = "Hello!World!";
public void setApplicationContext(ApplicationContext context) {
this.applicationContext =
public void setHelloWord(String helloWord) {
this.helloWord = helloW
public String getHelloWord() {
applicationContext.publishEvent(
new PropertyGettedEvent("[" + helloWord + "] is getted"));
return helloW
& 3. BeanFactoryPostProcessor,这个PostProcessor通常是用来处理在BeanFactory创建后的扩展接口。一个例子如下,当注入这个bean以后,它便会在BeanFactory创建完毕自动打印注入的bean数量:
public class BeanCounter implements BeanFactoryPostProcessor{
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
System.out.println(beanFactory.getBeanDefinitionCount());
&& 4. FactoryBean。FactoryBean是一种特殊的bean,这种bean允许注入到spring容器并用其生成真正的bean,所以可以这样定义,FactoryBean本身是一种bean,这种bean又有能够提供bean的能力。下面从FactoryBean的调用开始,讲到spring是如何使用这个bean的。
&& 要想区分普通bean和FactoryBean,spring也必须有判断他们并特殊处理的过程,这个过程就在AbstractBeanFactory的getObjectForBeanInstance中
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanI
Object object =
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
if (object == null) {
// Return bean instance from factory.
FactoryBean&?& factory = (FactoryBean&?&) beanI
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
& 可以看出来,如果是普通bean,就直接返回了,而如果是FactoryBean,最终调用会调用factory.getObject从而返回具体对象。如果将整个spring看做一个抽象工厂,生产抽象的bean时,则FactoryBean就是具体工厂,生产你需要的对象。
& spring中FactoryBean用法很多,举个比较常见的例子,集成hibernate的sessionFactory时一般会注入LocalSessionFactoryBean,但是这个sessionFactory实际上不是普通的bean,可以简单在配置文件中注入就能生产,它有很多定制的部分,于是spring让这个bean成为一个FactoryBean并控制其生产的对象。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具}

我要回帖

更多关于 java中bean是什么意思 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信