- 浏览: 139675 次
- 来自: ...
文章分类
最新评论
-
pch272215690:
考来考去的文章有意思吗
Java EE Servlet监听器 -
livemumu:
没有判断高位溢出。。。你把测试数据num改为50看看
java截取包含汉字字符串 -
lct456:
感谢,我总算运行成功了
Java读取XML文件之SAX篇 -
lct456:
感谢,我总算运行成功了
Java读取XML文件之SAX篇
Spring 2.0的新特性和应用实践
主题
Spring开源项目开始于2003年2月,现在框架正变得越来越强大。目前已经达到了超过一百万的下载量;在很多行业范围内成为事实上的标准;并且改变了企业Java应用的开发过程。最重要的是,它发展了大量而且忠诚的用户,他们理解框架的关键价值并且共享反馈,来帮助框架高速发展。Spring的使命也一直很清晰:
- 提供一种非入侵性编程模型。应用程序的代码应该尽可能地与框架解耦。
- 为内部基础设施提供一种优秀的解决方案,以便开发者能将注意力放在交付业务价值,而不是解决普通的问题。
- 使开发企业应用程序尽可能简单、增强,而不是减弱、机械。
在2006年10月份进入最终版的Spring 2.0,更加提升了这些价值。在核心团队在2005年佛罗里达Spring体验大会前研究发展特性时,我们发布了两个关键的主题——简易性和强大——突出作为Spring 2.0的主线,并且依旧忠实于Spring的使命。
某些决定很容易。从一开始,我们很清楚Spring 2.0将会完全向后兼容,或者说尽可能地完全向后兼容。尤其考虑到Spring在很多企业中作为一个事实上的标准这样一个定位,避免任何对用户体验的破坏 是非常重要的。幸运地是,Spring一直致力于非入侵,这样的目标就完全可以达到。
在十个月的Spring 2.0开发过程进行中,我们也需要考虑到一些Spring在2005到2006年的使用中越来越明显的趋势:
- Spring越来越多地被一些非常大的组织来使用,从战略的角度而不是只从项目角度来采用。这不仅意味着关于向后兼容的责任,而且是与大量不同类别的用户相关的挑战。
- 越来越多数目的优秀的第三方软件产品正在内部使用Spring,并需要容器的配置优化和灵活性。这样的例子很多,这里简单列举几个:
- 即将发布的BEA WebLogic Server 10,使用了Spring和Pitchfork项目来执行注入和拦截。
- BEA WebLogic Real Time(WLRT),来自于BEA的一种高端产品,致力于像前端办公交易这样的应用,需要很低的等待时间。
- 大量广泛使用的开源产品,比如Mule、ServiceMix以及Apache JetSpeed门户容器。
- 一些企业厂商使用Spring集成他们自己的产品,比如GigaSpaces,Terracotta和Tangosol等。尤其是网格空间的公司,正在逐步投入Spring作为编程模型的选择。
- Oracle的SCA实现,以及不同的其他Oracle产品。
因此我们需要确保当Spring变得对企业应用开发者更加友好的同时,也要迎合这些苛刻的用户。
从35000英尺
Spring 2.0的最大愿景是什么?
Spring 2.0提供了很大范围内的增强,其中最显著的可能是:
- 配置扩展:在Spring 2.0中,Spring支持可扩展的XML配置,使得使用自定义元素开发成为可能,它们为生成Spring bean的定义提供一种新层次的抽象。XML扩展机制同样提供了一些新的标签来简化许多普通的任务。
- 在AOP框架中有重要增强,使得既强大又更易于使用。
- 增强对Java 5的支持。
- 提供以动态语言实现Spring bean的能力,比如Groovy、JRuby和Beanshell,同时保留Spring组件模型的所有服务,比如依赖注入,方便的声明性服务以及AOP。
- 以及许多新的特征,包括一个Portlet MVC框架,“消息驱动POJO”,与新的API的集成,包括JAVA持久化API(JPA),以及一个异步任务执行框架。
有许多表面上不是很明显的特征,但仍然很重要:
- 对Ioc容器更进一步的扩展,使得在Spring之上构建框架或产品更加容易。
- 对Spring特有的集成测试支持的改善。
- 提供AspectJ来暴露Spring核心功能给使用AspectJ和Spring的用户,比如事务管理和依赖注入。
重要的是,这些特性被设计以和谐的整体来一起运行。
概述
这篇文章分为两部分。在第一部分(就是本文),我们将会谈到核心容器,XML配置扩展,AOP增强,以及特定于Java 5的特征。
在第二部分,我们将会谈到消息,对动态语言的支持,Java持久化API以及Web层的增强。也会看一下表面以下的一些改进。
现在就让我们更深入地研究一些新的特性,并且使用一些代码范例来描述它们。
XML配置扩展
在Spring 2.0中最明显的增强就是XML配置。
Spring Ioc容器实际上是独立于元数据的表示的,比如XML。Spring以Java对象(BeanDefinition以及它的子接口)的形式拥有自己的内部元数据。有一个对XML配置补充的研究,比如使用注解的Java配置。
然而在今天,XML是被最多用在配置Spring上的,这就是Spring核心中配置改进的焦点。
Spring 2.0中XML的增强巧妙概括了简易性和强大的主题:它们简化执行某些普通的任务,但是也使得一些额外的高级任务成为可能。
目标
传统上,在Spring的XML配置语法和Spring的内部元数据之间有一对一的关系。一个元素产生一个BeanDefinition。
这通常就是我们想要的,并且对于配置那些框架并不了解的应用程序类,也是理想的。
但是,如果框架应该了解一个可能被反复使用的特定的类呢,比如象JndiObjectFactory这样的普通的类,用来从JNDI寻找对象,并将其作为可注入的对象注入Spring容器,或者如果一些Bean定义只是在一起使用时才有意义呢?
这样,一种新的抽象形式就能带来重要的好处。
考虑一下下面这个例子,关于JNDI的lookup:
<bean class="org.springframework.jndi.JndiObjectFactoryBean" id="dataSource">
<property value="jdbc/jpetsore" name="jndiName">
</property></bean>
这当然要好过以前那些实现Service Locator的令人厌恶的日子,但它并不完美。我们会一直使用这个相同的类。并且(除非我们使用Java 5)没有一种机制来指明“jndiName”属性是必需的,而其他的属性都是可选的。
Spring 2.0添加了一个方便的“jee”命名空间,其中包括允许我们执行同样的JNDI lookup的标签,就像下面这样:
<jee:jndi-lookup jndi-name="jdbc/jpetstore" id="dataSource"></jee:jndi-lookup>
这个比较简单而且清楚。它清晰地表达了意图而且更加简洁。而且schema抓住了jndiName属性是必需的这样一个事实,并有方便的工具支持。其他可选的属性同样在这个schema中得以表达,就像下面这个例子:
<jee:jndi-lookup id="simple">
jndi-name="jdbc/MyDataSource"
cache="true"
resource-ref="true"
lookup-on-startup="false"
expected-type="com.myapp.DefaultFoo"
proxy-interface="com.myapp.Foo"/></jee:jndi-lookup>
请注意在这样一个相对简单的示例中,attribute的名称几乎和被配置的类中property名称一样,这不是必需的。没有必要做一个命名上的 对应,或者在attribute和property之间做一对一的对应。我们同样能够处理子元素内容。而且,正如我早先提到的,我们可以从一个扩展标签产 生我们想要的任意数目的bean定义。
现在让我们来考虑一个更加复杂的例子,其中我们要使用自定义标签的能力来产生不止一个bean定义。
从Spring 1.2开始,Spring就能够识别@Transactional注解,并通过代理来使受影响的bean变成事务。这导致了一种简单的部署模型——简单地 添加注解过的bean,它们就能自动变得可以处理事务——但是建立这样模型需要一些令人心烦的戏法。为了所需的合作对象,需要三个bean定义——一个 Spring AOP Advisor,一个TransactionInterceptor,以及一个DefaultAdvisorAutoProxyCreator来引发自动 的代理。这些bean定义组成了一个咒语,能够在不同的应用程序以不变的状态使用,但是暴露了多过用户不需要知道的细节:
<bean>
class="org.springframework...DefaultAdvisorAutoProxyCreator"/>
<bean class="org.springframework...&lt;b&gt;TransactionAttributeSourceAdvisor</b>">
<property transactioninterceptor="" name="transactionInterceptor&lt;br /> ref=">
</property>
<bean id="transactionInterceptor">
class="org.springframework...TransactionInterceptor">
<property name="transactionManager">
ref="transactionManager"/>
<property name="transactionAttributeSource">
<bean>
class="org.springframework...AnnotationsTransactionAttributeSource">
</bean>
</property>
</property> </bean></bean></bean>
这是错误的抽象层次。你并不需要看到Spring AOP框架如何控制事务管理这种层次的细节,本意不需要这样的清晰。Spring 2.0在新的“tx”命名空间中提供了一个标签,来替换所有这些定义,像下面这样:
<tx:annotation-driven></tx:annotation-driven>
这个简便的标签达到了相同的效果。这个标签清楚地表达了意图——自动识别事务注解。那三个bean定义仍然通过底层的扩展标签来创建,但那现在是框架的事情了,而不是用户的。
Spring 2.0扩展标签可以在必要时定义它自己的attribute以及子元素结构。定义命名空间的开发者完全可控。处理Spring 2.0扩展标签的NamespaceHandler可以从一个扩展标签创建任意数目的bean定义。
为了使用扩展标签,要使用XML schema而不是DTD,并且导入相关的命名空间。缺省的命名空间应该是beans schema。下面的“tx”命名空间的例子,允许使用<tx:annotation-driven>:</tx:annotation-driven>
<beans xmlns="http://www.springframework.org/schema/beans">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"></beans>
扩展标签可以和正规的bean定义混合使用,可以引入任意数目的命名空间,并在同一个文档中使用。
方便的命名空间
Spring 2.0提供一些方便的命名空间。其中最重要的是:
- 事务管理(“tx”):在Spring 2.0中使Spring bean能够处理事务变得相当容易,就像我们看到的那样。它同样使定义“transaction attributes”来映射事务行为到方法上变得简单的多。
- AOP(“aop”):Spring 2.0中专门的用来AOP配置的标签比以前更加简洁,Ioc容器不再需要依赖AOP框架。
- Java EE(“jee”):这样简化了对JNDI和其他Java EE API的使用,正如我们看到的那样。EJB lookup比JNDI lookup获得的简单性还要多。
- 动态语言(“lang”):以动态语言简化bean的定义——Spring 2.0的一个新特性。
- Utils(util):简化加载java.util.Properties对象和其他通用的任务。
在Spring2.1以及往后版本中,将会加入更多的命名空间,来将简单性引入新的领域。简化Spring MVC和JPA使用的命名空间可能会最先加入到核心中去。
第三方配置扩展
作为一种扩展机制,Spring 2.0命名空间最重要的可能性是在Spring核心的外围。
许多产品构建于Spring基础之上,它们的配置可以使用命名空间来变得更加简单。一个很好的例子是Acegi Security for Spring(将在2007年早些时候改名为Spring Security),它需要配置一些协作bean的定义。Spring 2.0的命名空间会使这变得非常简单。再一次更加清楚地表达了简单性的意图。
许多产品和Spring紧密集成,这样的好处不言而喻。Tangosol对Coherence的集成就是现成的案例。
其他潜在的例子包括支持Spring配置的产品,比如IBM的ObjectGrid。虽然ObjectGrid目前没有在内部使用Spring,但 它被设计成通过Java来配置,使得能更加容易地集成到基于Spring的应用程序中。扩展schema会让这个变得相当简单。
一个XML文档使用某个扩展标签作为顶层的元素是可能的。这样避免需要通过命名空间给扩展schema元素加上前缀,意味着这样的配置看起来更自然一些,而非以Spring为中心的。(通常,元素是在缺省的命名空间,因此传统的Spring bean定义并不需要前缀。)
随着时间过去,和JSP自定义标签的发展,经验会通过实证明了的价值引出通用目的的标签。我们期望用户来创建命名空间的库,来让这个社区受益。
实现XML扩展
实现命名空间相对简单。它分三步:
- 定义你的XML schema。这是最困难的一步,需要有合适的工具。对于schema没有限制,当然你需要明白它是如何在运行时引导BeanDefinition的生成的。
- 实现NamespaceHandler接口,从你的schema中的元素和属性来产生BeanDefinition。
- 编辑一个专门的注册文件,spring.handlers,来让Spring知道新建的NamespaceHandler类。
Spring配备的spring.handlers文件显示了“标准”的命名空间是如何配置的:
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
你可以在不同的/META-INF目录拥有多个spring.handlers文件。Spring会在运行时合并它们。
一旦遵循了这些步骤,就可以使用你的新的扩展。
NameSpaceHandler接口并不难实现。它采用W3C DOM元素,并通过处理它们来生成BeanDefinition元数据。Spring解析XML:你的代码仅仅需要遍历XML树。
public interface NamespaceHandler {
void init();
BeanDefinition parse(Element element, ParserContext parserContext);
BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext);
}
parse()方法是最重要的,它负责将BeanDefinitions添加到提供的上下文中。
同样要注意decorate()方法。NamespaceHandler同样可以装饰一个包含的bean定义,就像下面这个创建作用域内的代理的语法所显示的:
<bean id="</font">"scopedList" class="java.util.ArrayList" scope="request">
<aop:scoped-proxy>
</aop:scoped-proxy></bean>
<aop:scoped-proxy>标签用来修饰包含它的标准的<bean>元素;如果它能够访问BeanDefinition,它就能对BeanDefinition进行修改。<aop:scoped-proxy></aop:scoped-proxy></bean></aop:scoped-proxy>
为了简化BeanDefinition元数据的生成,Spring 2.0引入了一种方便的新的BeanDefinitionBuilder类,提供一种流畅的、构建器风格的API。开始实现 NamespaceHandlers的最佳指导是那些存在于Spring核心中的类。其中UtilNamespaceHandler是个相对简单的例子; 而AopNamespaceHandler是个比较高级的例子,它解析了一个复杂的子元素结构。
最佳实践:什么时候应该定义你自己的命名空间?
你有锤子并不意味着其他一切都是钉子。正如我们已经看到的,Spring 2.0的XML扩展机制在很多案例中交付了很大的价值。然而,如果没有很好的理由就不应该使用它。因为XML扩展标签是一种新的抽象,它同样提供了一些需 要学习的新的内容。Spring的正规的XML格式对成千上万的开发者来说已经很熟悉了,甚至对那些新接触Spring的人都是用直觉就可以判断的。 Spring XML文件提供了易于理解的某个应用程序结构的蓝图。如果过度配置使用了不熟悉的自定义标签,就没什么必要了。
让我们在这个领域内考虑一些相关的经验。JSP自定义标签是个很好的例子。最终它们通过设计得很棒的标签库,比如JSTL,Struts和 Spring MVC的标签库,产生了真实的价值。但在早些年,它们会引起厌恶,甚至是混乱的JSP页面。(我在这里可以根据经验来解释,因为我自己实现了一两个这样的 标签库)。
把命名空间处理器看作是一个重要的新的扩展点,以及对Spring很有价值的新的抽象。它们对于那些在Spring之上构建第三方产品的人来说非常 棒;它们对于非常大型的项目也很有用。很快就会发现,没有了它们,很难想象生活会变成什么样子。但是最终用户还是应该对实现它们持谨慎态度,但使用没有问 题。
当然,伴随Spring提供的方便的扩展标签,比如aop,tx以及jee命名空间,将很快成为Spring配置词表的核心部分,就跟元素一样被广泛了解。你当然应该优先使用这些,而不是传统的冗长的方式,来完成相同的任务。
语法糖
转向使用schema也允许一点点快捷方式,比如对property值使用attribute而不是子元素。这些attribute不会被验证,但 因为我们使用的是XML schema,而不是DTD,我们仍然可以保留所有其他的验证。因为attribute名称就是property名称,XML验证不会再添加任何东西;这 是基于Java的验证的问题,而不是XML结构的。
考虑一下下面这个Java对象,它有两个简单的property,以及对一个关联对象的依赖:
public class Person {
private int age;
private String name;
private House house;
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setHouse(House house) {
this.house = house;
}
}
可以像下面这样使用XML进行配置:
"1.0" encoding="UTF-8"?>
<beans xmlns="</font">"http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="</font">"com.interface21.spring2.ioc.Person"
p:name="Tony"
p:age="53"
p:house-ref="number10"
/>
<bean class="</font">"com.interface21.spring2.ioc.House"
id="number10"
p:name="10 Downing Street"
/>
</bean></bean></beans>
请注意property是如何通过使用attribute来提供的,而不是元素。这样使用了特殊命名空间“p”的魔力。这个命名空间并没有验证,但允许使用attribute名称来和Java property名称进行匹配。
通过简单的几句,我们就简化了使用“p”命名空间中的property名称。就像“p:name”。当注入对其他Spring bean的引用时,使用“-ref”后缀,就像“p:house-ref”。
这种快捷的语法在你想要使用autowiring时尤其方便。比如,考虑下面的变量:
<bean class="&lt;font color=">com.interface21.spring2.ioc.Person"
autowire="byType"
p:name="Tony"
p:age="53"
/></bean>
这里我们没有设置“house”property,因为autowiring会考虑它。你甚至可以使用在<beans>元素层次使用default-autowire来在整个文件使用autowiring。</beans>
下面这个来自于Spring 1.0或者 1.1的用法演示了Spring配置在最近两个主要的发布版本中(1.2和2.0)减少了多少数目的尖括号。
<bean class="</font">"com.interface21.spring2.ioc.Person">
<property name="name"><value>"Tony"</value></property>
<property name="age"><value>"53"</value></property>
<property name="house"><ref local="</font">"number10" /></ref>
</property> </bean>
在Spring1.2中,我们引入了“value”和“ref”attribute,在大多数情况下不需要子元素,而在Spring 2.0中则可以更纯粹和简单地使用attribute。
当然,传统的XML格式可以继续工作。当property值很复杂,而且不合法或者不能读作一个attribute值时,就可以使用它们(传统的XML格式)。而且,当然,没有必要重写已经存在的配置文件。
除了XML配置扩展,在Spring Ioc容其中还有很多其他的新的特性。
其他Ioc容器增强
新的bean作用域
和XMl扩展一起,最重要的新的Ioc容器特性就是对于bean生命周期管理的新增的自定义作用域。
1.背景
Spring之前为bean提供了两种作用域:单例和原型(或者叫非单例)。
Singleton bean是一个在所属容器上下文中的单例对象。在容器的生命周期中只会有一个实例存在,当容器关闭,它就会向所有需要知道容器关闭事件的单例bean发送事件通知——比如,关闭任何可以管理的资源,像连接池。
Prototype bean是任何时候通过注入到另外一个bean而被引用,或者是对所属容器上getBean()调用的响应时创建的。在这种情况下,bean定义与一个单 个对象没有关系,而是一个用来创建对象的配方。每个创建好的实例会有完全相同的配置,但会有不同的身份。Spring容器不会持有对原型的引用;它的生命 周期由获得它的那段代码来负责。
在Spring 2.0中,我们添加了自定义作用域的能力。可以给它们起任何名字。某个自定义作用域通常与能够管理对象实例的后端存储相对应。在这种情况下,Spring提供了它熟悉的编程模型,支持注入和查找,而且后端存储提供了作用域内对象的实例管理。
典型的后端存储有:
- HTTP session
- Clustered cache
- 其他持久化存储
2.Web作用域
对于这个特性,最通常的需求是关于在web应用程序HTTP session中透明存储对象。这在Spring 2.0中得到很方便的支持。因为这种需求很普通,所以举例会很容易:
考虑下面这个bean的定义:
<bean scope="session" class="com.foo.UserPreferences" id="userPreferences"></bean>
这里我们指定了“session”作用域而不是缺省的“singleton”。作用域可以指定成任何名字,但在Web应用程序中提供“session”和“request”便于使用。
当我们通过名称“userPreferences”调用getBean()时,Spring会很明显地从当前HTTP Session中找出UserPreference对象。如果没找到UserPreferences对象,Spring就会创建一个。注入使得可以为用户 描绘一个可以自定义的预配置的UserPreferences。
为了让它工作起来,你需要在你的web.xml文件中像下面这样定义一个过滤器。它会在底层处理一个ThreadLocal绑定,以便Spring能够知道去哪个HTTP Session对象中去查找。
<web-app>
...
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener></listener-class>
</listener>
...
</web-app>
这样就解决了查找的问题。但通常我们宁愿使用API尽量少的注入风格。如果我们想要把“userPreferences”bean注入到其他 bean中去会发生什么呢,哪个会有更长的生命周期呢?比如,如果我们想在像下面这样的一个单例Spring MVC控制器中采用单独的UserPreferences对象时,又会发生什么呢:
public class UserController extends AbstractController {
private UserPreferences userPreferences;
public void setUserPreferences(UserPreferences userPreferences) { this.userPreferences = userPreferences;
}
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// do work with this.userPreferences
// Will relate to current user }
}
在这个案例中,我们想要“非常及时”的注入,对短期存在的UserPreferences对象的引用是在被注入者使用的时候解析的。
通常有这样的误解,就是Spring注入是静态的,因此必然是无状态的。这并不正确。因为Spring有一个复杂的基于代理的AOP框架,它能在运行时通过提供这样“非常及时”的功能来隐藏查找的动作。因为Ioc容器控制着注入的内容,它能注入一个隐藏了需要查找的代理。
我们可以很容易地通知容器来执行这样的代理,像下面这样。我们使用一个子元素来修饰userPreferences bean定义,<aop:scoped-proxy>:</aop:scoped-proxy>
<bean class="com.foo.UserPreferences" id="userPreferences">scope="session">
<aop:scoped-proxy></aop:scoped-proxy>
</bean>
<!---->
<bean class="com.mycompany.web.UserController" id="userController">
<!---->
<property ref="userPreferences" name="userPreferences">
</property>
</bean>
现在解析会如期动态地发生;UserController中的userPreferences实例变量就会是从HTTP Session中解析出正确UserPreferences对象的代理。我们不需要直接跟HTTP Session对象打交道,而且可以轻松地对UserController进行单元测试,而不需要一个mock HttpSession对象。
另外一种获得“非常及时”的注入的方式是使用一个查找方法。这是一个自从Spring 1.1就存在的技术,它使生命周期长的bean(通常是单例)能依赖一个潜在的生命周期短的bean。容器能够重载一个抽象(或者具体)的方法来在方法被 调用时返回执行getBean()调用的结果。
在这个例子中,我们没有在被注入者中定义一个实例变量,而是定义了一个返回所需对象的抽象方法。方法必须是公有的或者受保护的:
public abstract class UserController extends AbstractController {
protected abstract UserPreferences getUserPreferences();
@Override protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// do work with object returned by getUserPreferences()
// Will relate to current user }
}
在这个例子中,没有必要使用一个作用域内的代理。我们改变了被注入对象的bean定义,而不是被注入的bean。XML配置看起来应该是这样:
<bean class="com.foo.UserPreferences" id="userPreferences">scope="session" />
<!---->
<bean class="com.mycompany.web.UserController" id="userController">
<!---->
<lookup-method bean="userPreferences" name="getUserPreferences">
</lookup-method>
</bean></bean>
这种机制需要类路径中包含CGLIB。
3.其他可能性
无疑,在真实的Spring风格中,底层的机制是可插拔的,而不是绑定到Web层的。比如,Tangosol Coherence作用域可以像下面这样使用,通过Tangosol和Interface21提供的“datagrid”命名空间。
<beans xmlns="http://www.springframework.org/schema/beans">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:datagrid="http://schemas.tangosol.com/schema/datagrid-for-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://schemas.tangosol.com/schema/datagrid-for-spring
http://schemas.tangosol.com/schema/datagrid-for-spring/datagrid-for-spring.xsd">
<datagrid:member>
<bean scope="datagrid" class="Person" id="brian">
<aop:scoped-proxy>
<property value="brian" name="firstName">
<property value="oliver" name="lastName">
<property value="21" name="age">
</property>
</property> </property></aop:scoped-proxy></bean></datagrid:member></beans>
在一个“datagrid”作用域内声明一个bean,意味着bean的状态管理是由Coherence来执行,在一个Clustered Cache中,而不是在本地的服务器上。当然,bean是由Spring来实例化和注入的,而且可以从Spring服务中受益。我们预见特定作用域内的 bean会在SOA和批处理的环境中非常有用,并且期望能在将来Spring的版本中添加更多方便的bean作用域。
4.自定义作用域
定义你自己的作用域很简单。参考手册详细解释了这个过程。你将需要一种策略来辨别如何在当前的作用域内解析出对象。典型的情况下,这会涉及到ThreadLocal,就像Web作用域在底层所做的那样。
类型推断
如果你运行的是Java 5,Spring 2.0会从它新的能力中获益,比如泛型。比如,考虑一下下面这个类:
public class DependsOnLists {
private List plainList;
private List<float> floatList;
public List<float> getFloatList() {
return floatList;
}
public void setFloatList(List<float> floatList) {
this.floatList = floatList;
}
public List getPlainList() {
return plainList;
}
public void setPlainList(List plainList) {
this.plainList = plainList;
}
} </float></float></float>
“plainList”属性是个旧式风格的集合,而“flodatList”属性有个类型化的说明。
考虑下面的Spring配置:
<bean color="#0000ff" class="&lt;font">"com.interface21.spring2.ioc.DependsOnLists">
<property color="#0000ff" name="&lt;font">"plainList"></property>
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</bean>
<property color="#0000ff" name="&lt;font">"floatList"></property>
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
Spring会正确地为“floatList”属性填上浮点数,而不是字符串,因为它能非常聪明地意识到它需要执行类型转换。
下面的测试演示了这种情况:
public class GenericListTest extends
AbstractDependencyInjectionSpringContextTests {
private DependsOnLists dependsOnLists;
public void setDependsOnLists(DependsOnLists dependsOnLists) {
this.dependsOnLists = dependsOnLists;
}
@Override
protected String[] getConfigLocations() {
return new String[] { "/com/interface21/spring2/ioc/inference.xml" };
}
public void testLists() {
List plainList = dependsOnLists.getPlainList();
List<float> floatList = dependsOnLists.getFloatList();
for (Object o : plainList) {
assertTrue(o instanceof String);
System.out.println("Value='" + o + "', class=" +
o.getClass().getName());
}
for (Float f : floatList) {
System.out.println("Value='" + f + "', class=" +
f.getClass().getName());
}
}
}</float>
输出看起来会像下面这样:
Value='1', class=java.lang.String
Value='2', class=java.lang.String
Value='3', class=java.lang.String
Value='1.0', class=java.lang.Float
Value='2.0', class=java.lang.Float
Value='3.0', class=java.lang.Float
新扩展点
在Ioc容器中有一些新的扩展点,包括:
- 额外的PostPostProcessor钩子,为像Pitchfork这样的项目提供更强大的能力,来处理自定义注解,或者在Spring bean实例化和配置时执行其他操作。
- 添加任意元数据到BeanDefinition元数据的能力。添加信息很有用,虽然对Spring本身没有意义,但可以被构建于Spring之上的框架,或者像集群产品这样跟Spring集成的产品来处理。
这些主题主要和高级用户,以及那些使用Spring编写产品的人有关,这同样超出本篇文章的范围。但是理解Spring 2.0并不仅仅是在表面上增强,这很重要;它在底层完成了相当多的有难度的工作。
同样也有大量的增强是支持与OSGi的集成,形成Spring OSGi集成项目,它将OSGi的动态模块管理的能力与Spring组件模型相集成。这个工作会在Spring2.1中继续进行,会把Spring的JAR文件打包成OSGi的bundle。
AOP增强
在Spring 2.0中最激动人心的增强之一是关于Spring AOP,它变得更加便于使用而且更加强大,主要是通过复杂而成熟的AspectJ语言的支持功能来实现,而同时保留纯的基于代理的Java运行时。
我们一直坚信AOP(面向切面编程)很重要。为什么?因为它提供给我们一种新的思考程序结构的方法,能够解决很多纯OOP无法解决的问题——让我们能够在一个模块中实现某些需求,而不是以发散的方式实现。
为了理解这些好处,让我们考虑一些我们可以在需求中表达但无法直接用纯OO代码实现的情况。企业开发者使用一个通常的词汇表来让他们进行清楚的沟通。比如,像服务层,DAO层,Web层或者Web控制器这样的术语,这不需要什么解释。
许多需求是用这个词汇表中的术语来表达的。比如:
- 服务层应该是可以处理事务的。
- 当DAO操作失败时,SQLException或者其他特殊持久化技术的异常应该被翻译,以确保DAO接口不会有漏掉的抽象。
- 服务层对象不应该调用Web层,因为各层应该只依赖直接处在其下方的层。
- 由于并发相关操作的失败而导致失败的等幂业务服务可以重试。
虽然这些需求都是现实存在的,并来自于经验,但它们并不能用纯OOP来优雅地解决。为什么?主要有两个原因:
- 这些来自于我们词汇表的术语有意义,但它们并不是抽象。我们不能使用术语编程;我们需要抽象。
- 所有这些都是所谓横切关注点的例子。一个横切关注点,在用传统OO方法实现时,会分解成很多类和方法。比如,想象一下在跨DAO层遭遇特殊异常时要使用重试逻辑。这个关注点横切许多DAO方法,而且在传统的方式中会需要实现许多单独的修改。
AOP就是通过对横切关注点进行模块化,并让我们从普通的还可以编程的抽象的词汇表来表达术语,来解决这样问题的技术,这些抽象叫做切入点,我很快会再解释一些关于它们的细节。这种方法带来一些主要好处,比如:
- 因为减少了剪切粘贴风格的复制而减少代码行数。这在像异常转换和性能监测这样的try/catch/finally习惯用法中尤其有效。
- 在单个代码模块中捕捉这样需求的能力,提升可追踪能力。
- 在单个地方修补bug的能力,而不需要重新访问应用程序中许多位置。
- 确保横切关注点不混淆主要的业务逻辑——随着开发的进展,这很有可能成为危险之处。
- 开发者和团队之间更好的职责分离。比如,重试功能可以有单个开发者或者团队来编码,而不需要由许多开发者跨多个子系统进行编码。
因此AOP很重要,我们想提供最好的解决方案。
Spring AOP无疑是最广泛使用的AOP技术,归功于以下优点:
- 采用成本几近为零。
- 提供正确的切入点,这才称得上是AOP而不仅仅是拦截。
- 提供一个支持许多使用方式的灵活的框架,可编程也可通过XML。
然而,在Spring 2.0之前,Spring中的AOP有一些缺点:
- 不写Java代码,只能表达简单的切入点。并没有一种切入点表达语言来以字符串形式,简洁表达复杂的切入点,虽然RegexpMethodPointcutAdvisor允许定义简单正规的基于表达的切入点。
- 当配置复杂AOP使用场景时,XML配置会变得很复杂。泛型元素被用来配置AOP类;虽然这对一致性来说很棒,对切面和类提供DI和其他服务,但它没有一个专门的配置方法来得简洁。
- Spring AOP不适合通知细粒度的对象——对象需要由Spring管理或者通过编程被代理。
- 基于代理的方法的性能负载在少数案例中成为问题。
- 因 为Spring AOP分离了代理和目标(被修饰或者被通知的对象),如果某个目标方法调用了目标上的方法,就不会使用到代理,意味着AOP通知并不适用。AOP使用基于 代理的方法的正反面影响超出了本文的范围:有一些积极的因素(比如能够对同一个类的不同实例应用不同的通知),但主要还是消极的。
为了在Spring 2.0中增强这个重要领域,我们希望在它的优势上构建,同时解决缺点。
目标
最先的两个缺点也是最显著的。它们都跟切入点相关。后面的三个缺点在Spring用户的正常使用中很少发生,如果它们证明是的确有问题的,我们建议使用AspectJ。(就像你会看到的,这是Spring AOP直接的进步。)
XML配置扩展解决了关键的挑战之一。因为我们想要保持Spring模块的设计,我们过去不能在Spring DTD中提供特定于AOP的标签——因此在这种情况下需要依赖可以详细一点的通用配置。随着Spring 2.0的出现,这样的问题没有了,因为XML schema并不像DTD,它允许扩展。我们可以提供一个AOP命名空间,看起来能让Ioc容器识别AOP结构,但不会影响模块化。
AOP术语101:理解切入点和通知
让我们简要地修正一下某些AOP术语。如果你使用过AOP这些概念,可能对你来说很熟悉——这些概念是相同的,仅仅有一点不同,即更加优雅和强大的表达方式。
切入点是匹配规则。它在程序执行中确定应该应用某个切面的点的集合。这些点叫做连接点。在应用程序运行时,连接点随时会有,比如对象的实例化和方法的调用。在Spring AOP(所有版本)的案例中,唯一支持的连接点是公有方法的执行。
通知是可以被切面应用到连接点的行为。通知能在连接点之前或之后应用。通知的所有类型包括:
- Before advice:在连接点之前调用的通知。比如,记录方法调用即将发生的日志。
- After returning adive:如果在连接点的方法正常返回时调用的通知。
- AfterThrowing advice(在Spring1.x中叫做Throws通知):如果连接点的方法抛出一个特殊的异常时调用的通知。
- After advice:在连接点之后调用的通知,无论结果是什么。特别像Java中的finally。
- Around advice:能够完全控制是否执行连接点的通知。比如,用来在事务中封装某个方法调用,或者记录方法的执行时间。
切面是结合切入点和通知成一个模块方案,解决特殊的横切问题。
如果这有点抽象,请不要担心:代码示例会很快解释清楚的。
对在Spring 2.0和AspectJ的环境中关于AOP基础的更深讨论,请参考Adrian在InfoQ上很棒的文章,"Simplifying Enterprise Applications with Spring 2.0 and AspectJ."
为什么会是AspectJ切入点表达式?
迄今为止,我们讨论过的概念都是基本的AOP概念,对于Spring AOP或者AspectJ而且这并不特别,在Spring1.x中已经是存在的。那么为什么我们选择在Spring 2.0中采用AspectJ呢?
如果我们需要一种切入点表达语言,那么选择就会很简单。AspectJ有个思路很好,严格定义和充足文档的切入点语言。它最近实现了一个当在Java 5上运行时,能对采用Java 5语法的编码全面检查。它不仅有很棒的参考材料,而且很多书籍和文章都对它进行了介绍。
我们不相信重新发明的轮子,而且定义我们自己的切入点表达语言是不合理的。进一步而言,自从AspectWerkz在2005年早期和冰岛 AspectJ项目之后,很明显AspectJ是除了Spring 2.0之外唯一一个主流的AOP技术。因此关键的合并既是一种考虑也是一种技术优势。
新的XML语法
新的AOP命名空间允许Spring XML配置指定AspectJ切入点表达式,通过由切入点匹配的方法将通知指向任何Spring bean。
考虑一下我们上面看到的Person类。它有个age属性,以及一个增加age的birthday方法:
public void birthday() {
++age;
}
我们假设有这样的需求,任何时候调用birthday方法,我们都应该发送一张生日贺卡
相关推荐
YOLO系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中,文件名末尾是部分类别名称; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值; 【注】可以下拉页面,在资源详情处查看标签具体内容;
项目包含完整前后端源码和数据库文件 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 服务器:tomcat7
weixin138社区互助养老+ssm(论文+源码)_kaic.zip
光纤到户及通信基础设施报装申请表.docx
项目包含完整前后端源码和数据库文件 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 服务器:tomcat7
功能完善的电商数据智能爬虫采集系统项目全套技术资料.zip
YOLO系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中,文件名末尾是部分类别名称; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值; 【注】可以下拉页面,在资源详情处查看标签具体内容;
### Android程序开发初级教程(一):初识Android **平台概述** Google推出的Android操作系统平台已经正式亮相,这是一个基于Linux内核的开源操作系统。对于开发者而言,了解其架构和支持的开发语言至关重要。以下是Android平台的架构概览: **平台架构及功能** 1. **应用框架(Application Framework)**:包含可重用和可替换的组件,确保所有软件在该层面上的平等性。 2. **Dalvik虚拟机(Dalvik Virtual Machine)**:一个基于Linux的虚拟机,为Android应用提供运行环境。 3. **集成浏览器(Integrated Browser)**:基于开源WebKit引擎的浏览器,位于应用层。 4. **优化图形(Optimized Graphics)**:包括自定义的2D图形库和遵循OpenGL ES 1.0标准的3D实现。 5. **SQLite数据库**:用于数据存储。 6. **多媒体支持(Media Support)**:支持通用音频、视频以及多种图片格式(如MPEG4, H.264
内容概要:本文档是《组合数学答案-网络流传版.pdf》的内容,主要包含了排列组合的基础知识以及一些经典的组合数学题目。这些题目涵盖了从排列数计算、二项式定理的应用到容斥原理的实际应用等方面。通过对这些题目的解析,帮助读者加深对组合数学概念和技巧的理解。 适用人群:适合初学者和有一定基础的学习者。 使用场景及目标:可以在学习组合数学课程时作为练习题参考,也可以在复习考试或准备竞赛时使用,目的是提高解决组合数学问题的能力。 其他说明:文档中的题目覆盖了组合数学的基本知识点,适合逐步深入学习。每个题目都有详细的解答步骤,有助于读者掌握解题思路和方法。
.net core mvc在线考试系统asp.net考试系统源码考试管理系统 主要技术: 基于.net core mvc架构和sql server数据库,数据库访问采用EF core code first,前端采用vue.js和bootstrap。 功能模块: 系统包括前台和后台两个部分,分三种角色登录。 管理员登录后台,拥有科目管理,题库管理,考试管理,成绩管理,用户管理等功能。 教师登录后台,可进行题库管理,考试管理和成绩管理。 用户登录前台,可查看考试列表,参加考试,查看已考试的结果,修改密码等。 系统实现了国际化,支持中英两种语言。 源码打包: 包含全套源码,数据库文件,需求分析和代码说明文档。 运行环境: 运行需vs2019或者以上版本,sql server2012或者以上版本。
YOLO系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中,文件名末尾是部分类别名称; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值; 【注】可以下拉页面,在资源详情处查看标签具体内容;
包含了登陆注册、用户管理、部门管理、文件管理、权限管理、日志管理、个人中心、数据字典和代码生成这九个功能模块 系统采用了基于角色的访问控制,角色和菜单关联,一个角色可以配置多个菜单权限;然后再将用户和角色关联,一位用户可以赋予多个角色。这样用户就可以根据角色拿到该有的菜单权限,更方便管理者进行权限管控。 本系统还封装了文件管理功能,在其他模块如若要实现图片/文件上传预览时,前端只需导入现成的 Vue 组件即可实现(使用 viewerjs 依赖实现),后端只需定义 String 类型的实体类变量即可,无需再去研究文件上传预览的相关功能,简化了开发者的工作量。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。
三相10Kw光伏并网逆变器。包含全套理图 PCB 源代码
GJB 5236-2004 军用软件质量度量文档,本称准规定了车用软件产品的质重模型和基本的度量。本标准为确定车用软件质量需求和衡量军用 软件产品的能力提供了一个框架。
基于MATLAB车牌识别系统【GUI含界面】.zip。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。
【宿舍管理系统】是一种专为高校或住宿机构设计的信息化解决方案,旨在提高宿舍管理的效率和准确性。该系统包含了多项核心功能,如宿舍管理员管理、宿舍信息维护、查询、卫生检查以及电费缴纳等,旨在实现全面的宿舍运营自动化。 **宿舍管理员管理**功能允许指定的管理员进行用户权限分配和角色设定。这包括对管理员账户的创建、修改和删除,以及设置不同的操作权限,例如只读、编辑或管理员权限。通过这样的权限控制,可以确保数据的安全性和管理的规范性。 **宿舍添加与管理**是系统的基础模块。管理员可以录入宿舍的基本信息,如宿舍号、楼栋、楼层、房间类型(单人间、双人间等)、容纳人数、设施配置等。此外,系统还支持批量导入或导出宿舍信息,方便数据的备份和迁移。 **查询功能**是系统的重要组成部分,它允许管理员和学生根据不同的条件(如宿舍号、楼栋、学生姓名等)快速查找宿舍信息。此外,系统还可以生成各种统计报告,如宿舍占用率、空闲宿舍数量等,以便于决策者进行资源优化。 **卫生检查**功能则是对宿舍卫生状况进行定期评估。管理员可设定检查计划,包括检查周期、评分标准等,并记录每次检查的结果。系统能自动生成卫生报表,用于
YOLO系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中,文件名末尾是部分类别名称; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值; 【注】可以下拉页面,在资源详情处查看标签具体内容;
九缸星形发动机点火器3D
本项目可以作为小程序毕设项目,主要功能为音乐播放器,主要功能是:可以播放歌曲(采用mp3网络连接实现)、专辑封面播放时可以旋转,能够实现开始和暂停播放,可以点击下一首歌曲,主页面实现动态轮播图
出差审批单(表格模板).docx