在工作中碰到了好多的配置文件,具体来说是spring 中bean配置的parent的配置,搞的我一头雾水,仔细看一下spring中有关bean的配置,剖析一下,具体什么含义!
一、Spring IoC容器和beans的介绍
1、Spring框架实现控制反转(IoC)的原理。IoC又叫依赖注入(DI)。它描述了对象的定义和依赖的一个过程,也就是说,依赖的对象通过构造参数、工 厂方法参数或者属性注入,当对象实例化后依赖的对象才被创建,当创建bean后容 器注入这些依赖对象。这个过程基本上是反向的,因此命名为控制反转(IoC),它通过直接使用构造类来控制实例化,或者定义它们之间的依赖关系,或者类似于服务定位模式的一种机制。
2、org.springframework.beans 和 org.springframework.context 是Spring框 架中IoC容器的基础, BeanFactory 接口提供一种高级的配置机制能够管理任何 类型的对象。 ApplicationContext 是 BeanFactory 的子接口。它能更容易集 成Spring的AOP功能、消息资源处理(比如在国际化中使用)、事件发布和特定的 上下文应用层比如在网站应用中的 WebApplicationContext。 总之, BeanFactory 提供了配置框架和基本方法, ApplicationContext 添加 更多的企业特定的功能。 ApplicationContext 是 BeanFactory 的一个子接 口,在本章它被专门用于Spring的IoC容器描述。
3、在Spring中,由Spring IoC容器管理的对象叫做beans。 bean就是由Spring IoC容 器实例化、组装和以其他方式管理的对象。此外bean只是你应用中许多对象中的一 个。Beans以及他们之间的依赖关系是通过容器配置元数据反映出来。
二、spring中容器的介绍
1、org.springframework.context.ApplicationContext 接口代表了Spring Ioc容 器,它负责实例化、配置、组装之前的beans。容器通过读取配置元数据获取对象 的实例化、配置和组装的描述信息。它配置的0元数据用xml、Java注解或Java代码 表示。它允许你表示组成你应用的对象以及这些对象之间丰富的内部依赖关系。
2、Spring提供几个开箱即用的 ApplicationContext 接口的实现类。在独立应用程 序中通常创建一 个 ClassPathXmlApplicationContext 或 FileSystemXmlApplicationContext 实例对象。虽然XML是用于定义配置元数据的传统格式,你也可以指示容器使用 Java注解或代码作为元数据格式,但要通过提供少量XML配置来声明启用对这些附 加元数据格式的支持。
3、在大多数应用场景中,显示用户代码不需要实例化一个或多个Spring IoC容器的实 例。
三、bean 中的parent属性
这个在spring-framework 5.0官方文档中都很少见,但是在文档中还是有一点定义的,在定义事务代理的一个小块中找到了一点,也就值找到了这一点,呵呵了。。。
1、创建代理的父模板
特别是在定义事务代理时,最终可能有许多类似的代理定义。 使用父、子bean定 义,以及内部bean定义,可能会使代理的定义更加清晰和简明。
//定义代理父模板
<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
这个定义自身永远不会实例化,所以实际上是不完整的定义。 然后每个需要被创建的代理,只需要一个子bean的定义,将目标对象包装成一个内部类定义,因为目标对象永远不会直接被使用。
2、创建子bean
//简单的子bean定义
<bean id="myService" parent="txProxyTemplate">
<property name="target">
<bean class="org.springframework.samples.MyServiceImpl">
</bean>
</property>
</bean>
当然也可以覆盖父模板的属性,例如在本示例中,事务传播的设置:
<bean id="mySpecialService" parent="txProxyTemplate">
<property name="target">
<bean class="org.springframework.samples.MySpecialServiceImpl">
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="store*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
需要主意的是,在上面的示例中,我们通过 abstract 属性明确的将父bean标记为抽象定义, 就如前面介绍的子bean定义,因此该父bean永远不会被实例化。 应用上下文(不是简单的bean工厂)默认会预先实例化所有单例。 因此,重要的是,如果你有一个仅仅想作为模板的bean(父bean)定义,并且指定了该bean的 class, 那么你必须保证该bean的 abstract 属性被置为 tue ,否则应用上下文 会尝试在实际中预先实例化该bean。
总结:这个用法的好处就是可以优化代码,很多相同的代码可以抽取出来,直接放到父bean中,然后在子bean中增加一些独特的属性或者方法,简单整洁,扩展性强,但是,这里并不是继承关系,并不是extends,spring官方文档说是子bean将目标对象包装成一个内部类定义,这个具体在内存中如何存储以及调用不是很明白,这里存在一点点的问题,记录下来,我再研究一下内部类!!!
Java中的内部类:
内部类的访问特点:
A:内部类可以直接访问外部类的成员,包括私有。
B:外部类要访问内部类的成员,必须创建对象。