spring 2.x总结

Spring是分层的java SE/EE应用一站式的轻量级开源框架,以IOC和AOP为内核,提供了展示层spring mvc和持久层spring jdbc,以及业务层事务管理等众多的企业级应用技术。

相关的网站:

spring.jactiongroup.net

www.springside.org.cn

www.javaeye.com

spring的体系结构

spring共有1400个类,其框架按功能分为7个模块。



spring核心模块:实现了IOC的功能,将类与类之间的依赖关系从代码中脱离出来,用配置的方式进行依赖描述,其中BeanFactory是核心接口。

ApplicationContext模块:核心模块使得spring成为一个bean的容器。ApplicationContext构建在核心之上,扩展了BeanFactory,添加了i18n,Bean生命周期控制,框架事件体系,资源加载透明化,以及企业服务的支持如邮件、任务调度、jndi定位、ejb集成、远程访问等。

AOP模块:Aop是横切逻辑编程的思想。spring提供了满足Aop Alliance规范的实现,还整合了AspectJ这种AOP语言级的框架。

Spring DAO:Spring使用模板编程对原始的jdbc进行薄层的封装,简化了数据库操作,建立一套面向DAO层的异常体系,将各种检查型异常转为非检查型异常。提供了声明式的事务服务,将事务的管理从代码中剥离,仅专注于业务的实现。

ORM模块:Spring通过ORM模块提供了整合多种ORM框架的能力。

Spring Web模块:建立在ApplicationContext模块之上,提供各种Web应用的工具类,如通过Listener或Servlet初始化Spring容器,将Spring容器注册到web容器中,透明化文件上传,整合其他Web框架等。

Spring MVC模块:Spring自己提供一个完整的类似于struts或web work的MVC框架。

spring 2.0的新功能

1、简化配置文件的编写
1.x版本使用dtd格式,而2.x引入schema格式,提供了不同的名字空间,简化配置。

2.新的bean的作用域
1.x版本只支持单例singleton和原型prototype两个作用域,2.x提供三个依赖web环境的作用域,还允许通过钩子技术自定义bean的作用域。

3.AOP的增强
1.x中AO是xml格式来配置的。
2.x中引入全新的AOP命名空间,通过AspectJ切点表达式完成切面定义。
2.x开始支持通过@AspectJ注解定义切面,这样当对象是在容器外被创建时,会被静态织入,从而产生对容器的回调。进行领带关系的注入,而原来对容器外的对象,Spring是不能管理的。

4.持久层增强
2.x进行声明式事务配置更加简单,同时增强了JPA的支持。

5.展示层的增强
Spring MVC开始采用契约模式,意味着用户可以通过命名规范的约束来减少配置文件。

6.其它
开始动态脚本语言ruby groovy beanshell等。
提供简单的JMS容器,支持JMX和JCA,表明态度,全面支持J2EE规范。
通过TaskExecutor接口对JDK5.0新增的任务执行器进行封装,允许开发人员更灵活地开发和JDK版本无关的任务执行器。
通过注解和泛型,对对象进行静态注入。

何谓IOC?
Inverse of Control字面意为控制反转,即某一个接口具体实现类的选择控制权从调用类中移除,转交给第三方裁决。

Martin Fowler提出DI(Dependency Injection)的概念替代IOC,即调用类对接口实现类的依赖关系由第三方注入。

IOC的方式
工厂:代码中未完全消除依赖,而是发生了依赖转移。
容器:完全从代码中消除依赖,Spring提供了setter/构造子/接口注入。

BeanFactory和ApplicationContext的区别:
Bean工厂是spring框架中最核心的接口,提供了高级IOC的配置机制,它是SPRING框架的基础而面向SPRING本身,称之为IOC容器。
ApplicationContext构建在Bean工厂之上,提供更多面向应用的功能,面向程序员称之为Spring容器。

WebApplicationContext
专门为web应用准备的,它允许从相对WebRoot的路径中装配配置文件完成初始化,它扩展了ApplicationContext, WebApplicationContext定义了一个常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在服务器启动时,WebApplication实现就以此键存放在ServletContext中,Spring提供了一个工具类用于获取WebApplication实例。如下:
WebApplicationContextUtils.getWebApplicationContext(ServletContext sc)

WebApplicationContext必须在web容器启动的前提下才能初始化,因此Spring提供了两个专用于启动WebApplicationContext的Servlet和监听器。
org.springframework.web.context.ContextLoaderServlet
org.springframework.web.context.ContextLoaderListener

父子容器
Spring的IOC容器可以建立父子层级关联的容器体系。
子容器可以访问父容器中的bean,但父容器不能访问子容器中的bean,在容器内,bean的id必须唯一。但子容器可以拥有一个和父容器同id的bean.

注入方式的考虑
使用构造子注入的理由:
保证属性在bean实例化时设置好。
不需要为每个属性提供setter,更好地封装了类变量。
反对理由:
类的属性太多,构造函数的签名太复杂。
可选的属性,必须注入null。
有时会造成循环依赖。

注入参数详解
1、字面值
可用字符串表示的值用<value>注入。
如果字符串中包括5个特殊字符,可使用转义实体符号。
< &lt;
> &gt;
& &amp;
" &quot;
' &apos;
或者使用<![CDATA[包括特殊字符的字符串]]>

2、引用其它bean
<ref>元素有以下三个属性引用容器中其他的bean。
bean:引用同一个容器或父容器的bean.
local:引用同一个配置文件中定义的bean.
parent:引用父容器中的bean.
父了容器的关系可在构造容器时指定。
new ClasssPathXmlApplicationContext(new String[]{"配置文件",...},父容器引用);

3、内部Bean
如果一个bean只能被另一个bean使用,则可用内部bean的方法注入。
<bean ...>
    <property name="属性名">
        <bean class="类名">
            <property ...>
        </bean>
    </property>
</bean>
内部bean没有名字,即使提供id,name,scope也会被忽略。scope默认为prototype.

4、null值
spring将<value></value>视为空字符串。
空值为<null/>表示。

5、级联属性
<bean id="boss" class=".....Boss类">
    <property name="car.brand" value="benchi"/>
</bean>

public class Boss{
    private Car car=new Car();
    public Car getCar(){
        return car;
    }
    public void setCar(Car c){
        this.car=c;
    }
}

6、集合类型

Object[]和List用<list>

Set用<set>

Map用

<map>

    <entry>

        <key><ref .../></key>

        <value> ....</value>

    </entry>

</map>

properties用

<props>

    <prop key="字符串">字符串</prop>

</props>

其中map的key和值可以使用任何类型,而props只能使用字符串。

<bean>之间的关系:

1.继承

<bean id="parentBean" class="..." abstract="true"/>

<bean id="subBean" parent="parentBean"/>

其中abstract="true"表示不产生实例,后者继承前者的配置。注意不并等同于类的继承。

2.依赖

<ref>标签建立对其他bean的依赖关系,能保证实例化一个bean时,它所依赖的其他bean已初始化。

3.引用

<idref>

Bean的作用域

spring1.x的作用域有2个:singleton和prototype

spring 2.x中针对WebApplicationContext添加了新的作用域,request/session/globalSession.

1.x的版本采用singleton="true|false"

2.x的版本兼容以上写法,但推荐使用scope="作用域"

spring的默认作用域为singleton,在容器启动时会自动实例化所有的singleton的bean并缓存于容器之中。

好处:提前实例化可发现一些潜在的问题并加快了运行效率。

如果不希望提前实例化可以使用lazy-init="true"来控制,但如果该bean被其它bean所使用,则该设置会忽略。

prototype指多例,在默认情况下,spring会在启动时不实例化prototype的bean,而且spriing容器将prototype的bean交给调用者后就不管它的生命周期。

新增的3种作用域在使用之前要额外配置web.xml

在低版的web容器(servlet2.3)之前,用过滤器

org.springframework.web.filter.RequestContextFilter过滤所有的请求

在高版的web容器中用请求监听器配置。

org.springframework.web.context.request.RequestContextListener

将web相关作用域的Bean注入到singleton或prototype的bean中,我们需要如下配置。

1.声明aop的名字空间

xmlns:aop="http://www.springframework.org/shema/aop"

2.创建代理

<bean name="a" class="..." scope="request">

    <aop:scoped-proxy/>

</bean>

3.引用web作用域的bean

<bean id="b" class="...">

    <roperty name="..." ref="a"/>

</bean>

注入给b的a是动态生成的代理对象,增加了判断当前的b需要取得哪个请求相关的a。

基于@AspectJ和schema的AOP

在spring1.x中定义一个切面是比较麻烦的,需要实现专门的接口并进行一些较为复杂的配置。

在spring2.x中AOP已经焕然一新,用户可以使用@AspectJ注解非常容易地定义一个切面,不需要实现任何接口,对于没有使用JDK5.0的项目,则可以通过基于schema的配置定义切面其方便程度与@AspectJ相差无几。

着手使用@AspectJ

使用@AspectJ之前,JDK的版本是5.0以上。

需要spring/lib/asm的关联库(轻量级的字节码处理框架,因为java的反映已经无法获得入参名,用asm处理方法入参名)。

需要spring/lib/aspectJ注解类库及相应的解析类库。

用@AspectJ将一个POJO类定义为一个切面

@AspectJ                                                    //标识切面

public class ...{

    @Before ("execution (* greetTo(..))")    //定义切入点和增强类型

     public void ...(){

               //具体的增强逻辑

    }

}

通过编程的方式使用@AspectJ切面

AspectJProxyFactory f=new AspectJProxyFactory();

f.setTarget(...);      //设定目标对象

f.addAspect(....class);    //设定切面类

... proxy=f.getProxy();    //生成代理

通过配置使用@AspectJ切面

<bean id="target" class="..."/>   //定义目标对象

<bean class="@AspectJ切面类"/>

<bean class="org.springframework.aop.aspectj.annotaion.AnnotationAwareAspectJAutoProxyCreator"/>

如果使用基于schema的aop命名空间就更简单了。

将最后一句改为<aop:aspectj-autoproxy/>

@AspectJ语法基础

@AspectJ使用jdk5.0注解和正规的AspectJ5的切点表达式描述切面。

切点表达式函数

spring支持9个@AspectJ切点表达式函数

大致分为以下4种类型:

方法切点函数

execution()

方法匹配模式串

@annotation()

方法注解类名

方法入参切点函数

args()

类名

@args()

类型注解类名

目标类切点函数

within()

类名匹配串

target()

类名

@within()

类型注解类名

@target()

类型注解类名

代理类切点函数

this()

类名

函数入参中使用通配符

@AspectJ支持3种通配符

*匹配任意字符,但只能匹配一个元素。

..匹配任意字符,可以匹配多个元素,但在表示类时,必须和*联合使用,而在表示入参时可单独使用。

+表示按类型匹配指定类的所有类,仅能跟在类名后面。

@AspectJ函数按其是否支持通配符及支持程度可以分为3类。

支持所有的通配符execution(),within()

仅支持+通配符args(),this(),target()

不支配通配符@args(),@within(),@target(),@annotation

除了execution(),within()之外,其它函数除了可以指定类名外,也可以指定变量名,并将目标对象中的变量绑定到增强的方法中。

逻辑运算符

切点表达式由切点函数组成,切点函数之间还可以进行逻辑运算,组成切点。

&&与操作,相当于切点的交集,在配置文件中使用时可以用and

||或操作,相当于切点的并集,or是等效的操作符

!非操作,相当于切点的反集,not是等效的操作符

在spriing中使用and ,or ,not时,允许不在前后添加空格,如果not位于表达式的开头,则必须在开头添加一个空格,否则将产生解析错误。

不同的增强类型

@AspectJ为各种增强类型提供了不同的注解类,位于org.aspectj.lang.annotation包中,它们的留存期都是RetentionPollicy.RUNTIME,标注目标都是METHOD.

@Before

前置增强,相当于BeforeAdvice

@AfterReturning

后置增强,相当于AfterReturningAdvice

@Around

环绕增强,相当于MethodInterceptor

@AfterThrowing

抛出增强,相当于ThrowsAdvice

@After

Final增强,不管是抛出异常或正常退出,该增强都会执行,该增强没有相应的接口,可以把它看作为ThrowsAdvice和AfterReturningAdvice的混合物。

基于schema的配置切面

如果项目没有使用JDK5.0,那么无法使用基于@AspectJ注解的切面,Spriing提供了基于schema配置的方法,完全可代替基于@AspectJ注解声明切面的方式。

一个切面的配置例子

<aop:config proxy-target-class="true">//true表示CGLIB,false表示jdk动态代理

    <aop:aspect ref="包含增强方法的bean">

        <aop:before pointcut="target(类名) and execution (* 方法名(..))" method="增强的方法"/>

    </aop:aspect>

</aop:config>

一个<aop:aspect>元素定义一个切面,其内部可以定义多个增强

一个<aop:config>中可以定义多个切面

一个<aop:before>声明一个前置增强,并通过pointcut属性定义切点表达式,切点表达式的语法与@Aspect中所用的语法完全相同

前例中pointcut属性声明的切点是匿名的切点,它不能被其他增强或其他切面引用。

配置命名切点

<aop:pointcut id="切点名" expression="切点表达式"/>

该标记可以放在<aop:aspect>中,则只能在一个切面中被访问。

该标记可以放在<aop:aspect>外,则只能在所有切面中被访问。

每一种增强类型元素都拥有pointcut,point-ref,method这3个属性。

posted @ 2010-12-08 14:00  玩玩乐乐  阅读(908)  评论(0编辑  收藏  举报