`
gao_20022002
  • 浏览: 159981 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Spring之重点理解语句概念:核心技术

阅读更多

org.springframework.beans.factory.BeanFactory 是Spring IoC容器的实际代表者,IoC容器负责容纳此前所描述的bean,并对bean进行管理。
BeanFactory是IoC容器的核心接口。 它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
XmlBeanFactory的实现将以XML方式描述组成应用的对象 以及对象间的依赖关系。XmlBeanFactory类将获取此XML配 置元数据,并用它来构建一个完全可配置的系统或应用。
Spring IoC容器读取配置元数据,并通过它对应用中各个对象进行实例化、配置以及组装。
到目前为止,基于XML的元数据是最常用到的配置元数据格式。然而,它并 不是唯一的描述格式。Spring IoC容器在这一点上是 完全开放的。如本地文件 系统、Java CLASSPATH等。
bean定义与应用程序中实际使用的对象一一对应。通常情况下bean的定义包括:服务 层对象、数据访问层对象(DAO)、表示层对象、Hibernate SessionFactory对象、JMS Queue对象等等。通常bean的定义并不与容器中的领域对象相同,因为领域对象的创建和加载必须依赖具体的DAO和业务逻辑。
bean定义由BeanDefinition 对象来表示,该定义将包含以下信息:
1、全限定类名:这通常就是已定义bean的实际实现类。
2、bean行为的定义,这些定义将决定bean在容器中的行为(作用域、生命周期回调等等)
3、对其他bean的引用,这些引用bean也可以称之为协作bean(collaborators) 或依赖bean(dependencies)
4、创建bean实例时的其他配置设置。比如使用bean来定义连接池,可以通过属性或者构 造参数指定连接数,以及连接池大小限制等。
为每个bean定义包含的一组properties。
从本质上来说,bean定义描述了如何创建一个或多个对象实例。当需要的时候, 容器会从bean定义列表中取得一个指定的bean定义,并根据bean定义里面的配置元数据 使用反射机制来创建(或取得)一个实际的对象。
实例化bean:1、用构造器来实例化;2、使用静态工厂方法实例化;3、使用实例工厂方法实例化(class属性必须为空)。
从本质上讲,BeanFactory仅仅只是一个 维护bean定义以及相互依赖关系的高级工厂接口。通过BeanFactory 我们可以访问bean定义。
依赖注入(DI)背后的基本原理是对象之间的依赖关系(即一起工作的其它对象)只会通过以下几种方式来实现:构造器的参数、工厂方法的参数,或给由构造函数或者工厂方法创建的对象设置属性。
Spring容器的工作就是创建bean时注入那些依赖关系。相对于由bean自己来控制其实例化、直接在构造器中指定依赖关系或者类似服务定位器(Service Locator)模式这3种自主控制依赖关系注入的方法来说,控制从根本上发生了倒转,这也正是控制反转(Inversion of Control, IoC) 名字的由来。
bean自己不再担心对象之间的依赖关系。
DI(Dependence Inject)主要有两种注入方式,即Setter注入和构造器注入
在默认情况下,ApplicationContext实现中的bean采用提前实例化的singleton模式。在实际需要之前创建这些bean将带来时间与内存的开销。而这样做的好处就是ApplicationContext被加载的时候可以尽早的发现一些配置的问题。不过用户也可以根据需要采用延迟实例化来替代默认的singleton模式。
循环依赖:一个可能的解决方法就是修改源代码,将某些构造器注入改为setter注入。另一个解决方法就是完全放弃构造器注入,只使用setter注入。
对Bean配置进行“减肥”,第一种做法就是通过使用<property/>来定义值和对其他bean的引用(注入其他对象的方式三),另一个做法就是采用不同的属性定义格式(属性分离),第三个选择就是使用p名称空间(XML Schema定义)。
Bean的定义:name\class\depends-on\延迟初始化bean\自动装配(autowire)协作者\依赖检查\(方法注入)
在大部分情况下,容器中的bean都是singleton类型的。如果一个singleton bean要引用另外一个singleton bean,或者一个非singleton bean要引用另外一个非singleton bean时,通常情况下将一个bean定义为另一个bean的property值就可以了。不过对于具有不同生命周期的bean来说这样做就会有问题了,比如在调用一个singleton类型bean A的某个方法时,需要引用另一个非singleton(prototype)类型的bean B,对于bean A来说,容器只会创建一次,这样就没法在需要的时候每次让容器为bean A提供一个新的的bean B实例。
上述问题的一个解决办法就是放弃控制反转。另一种方法是Lookup方法注入,它利用了容器的覆盖受容器管理的bean方法的能力,从而返回指定名字的bean实例(内部机制是Spring利用了CGLIB库在运行时生成二进制代码功能,通过动态创建Lookup方法bean的子类而达到复写Lookup方法的目的)。还有一种很少用到的方法注入形式,该注入能使用bean的另一个方法实现去替换自定义的方法。
Spring Framework支持五种作用域(singleton、prototype、request、session、global session)(其中后三种只能用在基于web的Spring ApplicationContext)。
经典的GoF Singleton模式中所谓的对象范围是指在每一个ClassLoader中指定class创建的实例有且仅有一个。把Spring的singleton作用域描述成一个container对应一个bean实例最为贴切。亦即,假如在单个Spring容器内定义了某个指定class的bean,那么Spring容器将会创建一个且仅有一个由该bean定义指定的类实例。
根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。请注意,通常情况下,DAO不会被配置成prototype,因为DAO通常不会持有任何会话状态,因此应该使用singleton作用域。
Spring不能对一个prototype bean的整个生命周期负责(重要:让Spring容器释放被prototype作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用)。
Singleton beans和prototype-bean的依赖(“方法注入” )。
request、session以及global session 仅在基于web的应用中使用(不必关心你所采用的是什么web应用框架)。IllegalStateException异常(未知的bean作用域)
定制bean特性: 生命周期回调、了解自己BeanFactoryAware和BeanNameAware 。
Spring提供了几个标志接口(marker interface),这些接口用来改变容器中bean的行为,对于构造以及析构可以使用Bean属性替代,减少耦合,注意组合生命周期机制。
在一个非web应用的环境下使用Spring的IoC容器,如何正常关闭Spring IoC容器(注册钩子)。
如何从BeanFactory获取特定的Bean,即真正的了解自己。
bean定义的继承:从父bean继承构造器参数值、属性值以及覆盖父bean的方法,并且可以有选择地增加新的值;子Bean必须自己设置的:依赖、自动装配模式、依赖检查、singleton、作用域和延迟初始化。
Spring框架的IoC容器被设计为可扩展的。通常我们并不需要子类化各个BeanFactory或ApplicationContext实现类。而通过plugin各种集成接口实现来进行扩展。
1、用BeanPostProcessor定制bean:它定义了几个回调方法,实现该接口可提供自定义(或默认地来覆盖容器)的实例化逻辑、依赖解析逻辑等。(org.springframework.beans.factory.config.BeanPostProcessor)
2、用BeanFactoryPostProcessor定制配置元数据:Spring IoC容器允许BeanFactoryPostProcessor在容器实际实例化任何其它的bean之前读取配置元数据,并有可能修改它。(org.springframework.beans.factory.config.BeanFactoryPostProcessor)
3、使用FactoryBean定制实例化逻辑:插入到Spring IoC容器用来定制实例化逻辑的一个接口点。(org.springframework.beans.factory.FactoryBean)
beans包提供了以编程的方式管理和操控bean的基本功能,而context包下的ApplicationContext以一种更加面向框架的方式增强了BeanFactory的功能。
context包的核心是ApplicationContext接口,另外它还提供了以下的功能:
1、MessageSource, 提供国际化的消息访问
2、资源访问,如URL和文件
3、事件传播,实现了ApplicationListener接口的bean
4、载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
利用MessageSource实现国际化:ResourceBundleMessageSource和StaticMessageSource。
事件:ApplicationContext中的事件处理是通过ApplicationEvent类和ApplicationListener接口来提供的。这是标准的Observer设计模式。
Spring提供了五个标准事件:ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、ContextClosedEvent、RequestHandledEvent。
与BeanFactory通常以编程的方式被创建不同的是,ApplicationContext能以声明的方式创建,如使用ContextLoader。当然你也可以使用ApplicationContext的实现之一来以编程的方式创建ApplicationContext实例。
ContextLoader机制有两种方式,ContextLoaderListener 和ContextLoaderServlet。
SingletonBeanFactoryLocator和ContextSingletonBeanFactoryLocator(粘合代码和可怕的singleton问题??)。
基于注解的配置。
对受管组件的Classpath扫描:
{使用XML来指定配置元数据, 这些元数据会生成Spring容器中的每个BeanDefinition。
基于注解使用代码级的注解来提供大量配置元数据。 然而,“基础”bean定义还是显式地定义在XML文件中,注解只是用来驱动依赖注入的。
扫描classpath并匹配过滤器来隐式地检测候选组件 (candidate components)。}

Spring的 Resource 接口是为了提供更强的访问底层资源能力的抽象。(org.springframework.core.io.InputStreamSource )
Spring提供了很多 Resource 的实现: UrlResource、ClassPathResource、FileSystemResource、ServletContextResource 、InputStreamResource、ByteArrayResource。
ResourceLoader 接口由能返回(或者载入)Resource 实例的对象来实现。 所有的application context都实现了 ResourceLoader 接口, 因此它们可以用来获取Resource 实例。
ResourceLoaderAware 接口ResourceLoaderAware是特殊的标记接口,它希望拥有一个ResourceLoader 引用的对象。当实现了 ResourceLoaderAware接口的类部署到application context(比如受Spring管理的bean)中时,它会被application context识别为 ResourceLoaderAware。接着application context会调用setResourceLoader(ResourceLoader)方法,并把自身作为参数传入该方法(记住,所有Spring里的application context都实现了ResourceLoader接口)。 既然 ApplicationContext 就是ResourceLoader,那么该bean就可以实现 ApplicationContextAware接口并直接使用所提供的application context来载入资源,但是通常更适合使用特定的满足所有需要的 ResourceLoader实现。 这样一来,代码只需要依赖于可以看作辅助接口的资源载入接口,而不用依赖于整个Spring ApplicationContext 接口。
把Resource作为属性来配置:所有的application context注册并使用了能把 String 路径变为 Resource 对象的特殊 PropertyEditor JavaBeans。
application context构造器通常使用字符串或字符串数组作为资源的定位路径。ClassPathXmlApplicationContext会通过classpath载入并使用ClassPathResource,FileSystemXmlApplicationContext会通过文件系统从相对于当前工作目录中被载入。如果定位路径使用classpath前缀或标准的URL前缀,那它就会覆盖默认的Resource 类型。
Application context构造器中资源路径的值可以是简单的路径,即一对一映射到一个目标资源; 或者可以包含特殊的"classpath*:"前缀和Ant风格的正则表达式(用Spring的 PathMatcher 工具来匹配)。
Ant风格的pattern,注意重点了解。

Spring由Validator和DataBinder组成的validation验证包,主要被用于Spring的MVC框架。
BeanWrapper作为一个基础组件被用在了Spring框架中的很多地方。
Spring大量地使用了PropertyEditor(属性编辑器)。PropertyEditor的概念是JavaBean规范的一部分。它与BeanWrapper以及DataBinder三者之间有着密切的联系。
Spring提供的validator接口进行对象的校验。Validator接口与Errors协同工作,在Spring做校验的时候,它会将所有的校验错误汇总到Errors对象中去。ValidationUtils可以很好的参考。对复杂对象来说,实现Validator类来验证其内置的属性类当然也是可行的,但是为每个内置类的示例实现Validator可能是个更好的主意。
从错误代码到错误信息: MessageCodesResolver 和 DefaultMessageCodesResolver 。org.springframework.validation.Errors的方法rejectValue()了解。
Bean处理和BeanWrapper:
org.springframework.beans包遵循Sun发布的JavaBean标准。JavaBean是一个简单的含有一个默认无参数构造函数的Java类, 这个类中的属性遵循一定的命名规范,且具有setter和getter方法。
BeanWrapper接口以及它对应的实现BeanWrapperImpl:BeanWrapper提供了设置和获取属性值(单个的或者是批量的),获取属性描述信息、查询只读或者可写属性等功能。不仅如此,BeanWrapper还支持嵌套属性,你可以不受嵌套深度限制对子属性的值进行设置。所以,BeanWrapper无需任何辅助代码就可以支持标准JavaBean的PropertyChangeListeners和VetoableChangeListeners。除此之外,BeanWrapper还提供了设置索引属性的支持。通常情况下,我们不在应用程序中直接使用BeanWrapper而是使用DataBinder 和BeanFactory。
BeanWrapper:设置和获取属性值以及嵌套属性、内建的PropertyEditor实现
org.springframework.beans.PropertyEditors包实现内建属性编辑器,实现在Object和 String之间进行有效地转化。它们中的大多数已经默认在BeanWrapperImpl的实现类中注册好了。作为可配置的选项,你也可以注册你自己的属性编辑器实现去覆盖那些默认编辑器。

面向切面编程(AOP)通过提供另外一种思考程序结构的途经来弥补面向对象编程(OOP)的不足。纵切:在OOP中模块化的关键单元是类(classes)。横切:在AOP中模块化的单元则是切面。切面能对关注点进行模块化,例如横切多个类型和对象的事务管理(Spring 2.0允许用户选择使用更简单、更强大的基于模式或@AspectJ注解的方式来自定义切面。)。
Spring IoC容器并不依赖于AOP,这意味着你有权利选择是否使用AOP,AOP做为Spring IoC容器的一个补充,使它成为一个强大的中间件解决方案。
AOP在Spring Framework中的作用:
1、提供声明式企业服务,特别是为了替代EJB声明式服务。最重要的服务是声明性事务管理。
2、允许用户实现自定义切面,用AOP来完善OOP的使用。
AOP概念和术语:切面(Aspect)切面(Aspect)、通知(Advice)、切入点(Pointcut)、引入(Introduction)、目标对象(Target Object)、AOP代理(AOP Proxy)、织入(Weaving)。
通知类型:前置通知(Before advice)、后置通知(After returning advice)、异常通知(After throwing advice)、最终通知(After (finally) advice)、环绕通知(Around Advice)。
Spring AOP使用纯Java实现。它不需要专门的编译过程。Spring AOP不需要控制类装载器层次,因此它适用于J2EE web容器或应用服务器。
Spring并不是要提供最完整的AOP实现,相反的,它其实侧重于提供一种AOP实现和Spring IoC容器之间的整合,用于帮助解决在企业级开发中的常见问题。
Spring Framework一个重要的原则就是无侵入性(non-invasiveness):这个思想指你不应当被迫引入框架特定的类和接口到你的业务/领域模型中。然而,Spring Framework在某些地方给你一个是否引入Spring框架特定依赖到你的代码的选项。
Spring缺省使用J2SE 动态代理(dynamic proxies)来作为AOP的代理。 这样任何接口(或者接口集)都可以被代理。Spring也可以使用CGLIB代理。
Spring AOP中使用@AspectJ还是XML:
1、XML风格有两个缺点。第一是它不能完全将需求实现的地方封装到一个位置;第二是XML风格同@AspectJ风格所能表达的内容相比有更多的限制:仅仅支持"singleton"切面实例模型, 并且不能在XML中组合命名连接点的声明。
2、@AspectJ风格支持其它的实例模型以及更丰富的连接点组合。它具有将切面保持为一个模块单元的优点。 还有一个优点就是@AspectJ切面能被Spring AOP和AspectJ两者都理解。
Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理。如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。 若该目标对象没有实现任何接口,则创建一个CGLIB代理。

使用@AspectJ和基于Schema切面定义的AOP。
Spring的切入点模型使得切入点可以独立于通知(advice)类型进行重用,这就使得针对不同通知使用相同的pointcut成为可能。org.springframework.aop.Pointcut是最核心的接口,用来将通知应用于特定的类和方法。
Spring AOP中的切入点是Java类而不是语言的特性,所以可以声明自定义的切入点,不论是静态还是动态的。 org.springframework.aop.support.StaticMethodMatcherPointcut。
SPring AOP是怎样处理通知的?每个通知都是一个Spring bean。一个通知实例既可以被所有被通知的对象共享,也可以被每个被通知对象独占。 这根据设置类共享(per-class)或基于实例(per-instance)的参数来决定。
在Spring中最基础的通知类型是拦截环绕通知(interception around advice),Spring里使用方法拦截的环绕通知兼容AOP联盟接口。
在Spring里,一个Advisor是一个仅仅包含一个通知对象和与之关联的切入点表达式的切面。
如果你正在使用Spring IoC容器(即ApplicationContext或BeanFactory)来管理你的业务对象--这正是你应该做的--你也许会想要使用Spring中关于AOP的FactoryBean。
在Spring里创建一个AOP代理的基本方法是使用org.springframework.aop.framework.ProxyFactoryBean。 这个类对应用的切入点和通知提供了完整的控制能力。
像其它的FactoryBean实现一样,ProxyFactoryBean引入了一个间接层。如果你定义一个名为foo的ProxyFactoryBean, 引用foo的对象看到的将不是ProxyFactoryBean实例本身,而是一个ProxyFactoryBean实现里getObject() 方法所创建的对象。 这个方法将创建一个AOP代理,它包装了一个目标对象。使用ProxyFactoryBean或者其它IoC相关类带来的最重要的好处之一就是创建AOP代理,这意味着通知和切入点也可以由IoC来管理。
ProxyFactoryBean类本身也是一个JavaBean:指定你希望代理的目标对象、指定是否使用CGLIB。
对于一个目标对象,ProxyFactryBean是如何决定究竟创建一个基于JDK还是CGLIB的代理的??如果一个需要被代理的目标对象的类没有实现任何接口,那么一个基于CGLIB的代理将被创建。 因为JDK代理是基于接口的,没有接口意味着没有使用JDK进行代理的可能。
对接口进行代理:纯粹的JavaBean,使用匿名内部bean来隐藏目标和代理之间的区别。
对类进行代理:配置Spring使用CGLIB代理,而不是动态代理。这只需简单地把上面ProxyFactoryBean的proxyTargetClass属性设为true。
也许需要许多相似的代理定义,特别是定义事务性代理的时候。使用父子bean定义,以及内部bean定义,可以让代理定义大大得到极大的简化。如果你有一个(父)bean定义你希望仅仅作为模版使用,而这个定义说明了一个类,你必须把abstract参数设置为true,否则应用程序上下文将试图预先初始化它。
使用Spring通过编程创建AOP代理是很容易的。这使你可以使用Spring AOP而不必依赖于Spring IoC。
在创建了AOP代理之后,你能够使用org.springframework.aop.framework.Advised接口对它们进行管理。 任何AOP代理都能够被转型为这个接口,不论它实现了哪些其它接口。
到目前为止我们已经考虑了如何使用ProxyFactoryBean或者类似的工厂bean来显式创建AOP代理。Spring也允许我们使用“自动代理”的bean定义,可以自动对被选中的bean定义进行代理。
org.springframework.aop.framework.autoproxy包提供了下列标准自动代理创建器。
Spring提供了TargetSource的概念,由org.springframework.aop.TargetSource接口进行描述。 这个接口负责返回一个实现连接点的“目标对象(target object)”。每当AOP代理处理一个方法调用时都会向TargetSource的实现请求一个目标实例。 热交换目标源、池化目标源、 原型目标源、ThreadLocal目标源。
org.springframework.aop.framework.adapter包是一个SPI包,它允许添加新的自定义通知类型而无需修改核心框架。 对于自定义Advice类型的唯一的限制是它必须实现org.aopalliance.aop.Advice这个标记接口。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics