Spring的作用:
能够降低组件之间的耦合度,实现软件之间的解耦
可以使用Spring容器的众多服务,比如:事务管理器.当我们使用事务管理器时,开发人员不需要手动控制事务,也不需要处理复杂的事务传播.
Spring容器提供单例模式的支持
容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等.
容器提供了很多辅助器,这些类能够加快应用的开发,如:JdbcTemplate、HibernateTemplate等.
Spring提供了主流应用框架的支持,如:集成Hibernate、JPA、Struts等,便于应用程序的开发
Spring的核心技术是IoC(Inversion of Control)和AOP(Aspect-oriented programming).
IoC还有另一个名字,叫DI(Dependency Injection),称为"依赖注入".所谓依赖注入就是指,在运行期间,由外部容器动态地将依赖对象注入到组件中.
依赖注入有三种方式:
使用构造器注入
使用属性setter注入
使用Field注入(利用注解)
Bean的装配
Spring提供三种实例化Bean的方式:
使用类构造器的方式
<bean id=”唯一标识符” class=”完整类名”></bean>
使用静态工厂的方式
<bean id="唯一标识符" class="工厂的完整类名" factory-method="需要执行工厂的哪个方法的方法名" />
使用工厂实例的方式
<bean id=“唯一标识符1" class="工厂的完整类名"/> <bean id="唯一标识符2" factory-bean=“唯一标识符1" factory-method="需要执行工厂的哪个方法的方法名" />
Bean在实例化的时候默认只有一个,不管获得几次,都是同一个Bean,不过Spring提供了修改Bean作用域的属性,有几种取值:
singleton,prototype,request,session,global session.有几个都没什么用.
除了配置的注入方式以外,还可以使用注解的方式进行注入,在JAVA代码中使用@Autowired或@Resource注解方式进行装配.不过在装配之前,需要引入context命名空间,虽然Spring支持注解的解析,但是默认解析的"开关"没有打开,必须在配置文件里添加<context:annotation-config />标签,这个标签隐式的注册了Spring对注解进行解析的处理器:
AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,
PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor
@Autowired可以作用在构造器、字段和方法上,默认以类型进行查找,默认情况下它要求的依赖对象必须存在,如果可以允许不存在,则需要设置它的required属性值为false.如果想以名称进行查找,可以结合@Qualifier注解一起使用,如@Autowired @Qualifier("指定名称").@Qualifier注解还可以指定在构造器或者方法的参数在,如:
@Autowired public void setPersonDao(@Qualifier("personDao") PersonDao personDao) {//用于属性的set方法上 this.personDao = personDao; }
@Resource可以作用在类、方法和字段上,默认以名称进行查找,如果找不到相应的Bean,则以类型进行查找.如果指定了name属性,则只按名称进行查找.
另外,Spring还支持Bean的自动装配:
<bean id=“foo” class=“...Foo” autowire=“autowire type”>
autowire的取值包含(byType,byName,constructor,autodetecte),只用了解就行了,不常用,以免出现不可预知的后果.
此外,项目中通常会有上百个组件,如果这些组件全部采用在配置文件中通过Bean的方式来配置,则会明显增加配置文件的体积,查找和维护起来也会相关不便.所以,Spring2.5提供了自动扫描组件的方式来配置组件,它通过在类路径下寻找标了@Component、@Service、@Controller和@Repository注解的类,并把这些类纳入到Spring的容器中进行管理.
要使用自动扫描机制,需要引入context命名空间,并且需要在配置文件里面加上:
<context:component-scan base-package="包名"/>.
这个标签将扫描指定包(含子包)下的所有组件.并且把AutowiredAnnotationBeanPostProcessor 和CommonAnnotationBeanPostProcessor隐式地被包括进来以进行注解解析.
AOP--面向切面编程
如果目标对象实现了接口,则代理对象也实现同样的接口,否则使用cglib代理,则Spring有两种代理方式:
若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
备注:
对接口创建代理优于对类创建代理,因为这将产生更加松耦合的系统.
标记为final的方法无法得到通知,Spring需要为目标类产生子类,需要覆写被通知的方法,然后将通知织入.final方法不允许被覆写.
AOP中有几个概念,这些概念我们经常会用到,大数人也经常在程序中写出来,但是自己不知道:
连接点就是被拦截到的那个点,在Spring中,"点"指的是方法,因为Spring只支持方法类型的连接点.也就是说,哪个方法现在被拦截到了,我们就把这个方法称为连接点.
切入点就是我们要拦截哪些连接点.比如你的工作是查水表,你负责的那个区域就是切入点,你现在正在查的那家,就是连接点.
通知就是拦截到连接点之后要做的事情,比如乘地铁,你不带包就不用安检,如果你带了包,就要安检(被拦截到了),然后X射线检查你的包就是一个通知.通知分为:前置通知,后置通知,最终通知,异常通知,环绕通知五种.
是通知和切入点的结合,通知和切入点共同定义了关于切面的全部内容---它的功能、在何时和何地完成其功能,简单的说,通知所在的类,并且定义了切入点,那么这个类就是切面.
需要代理的对象.
把切面应用到目标对象来创建一个代理对象的过程就叫织入.
引入就是在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
要进行AOP编程,首先就要引入aop命名空间,Spring提供了两种切面方式,实际工作中我们可以任选其一:
基于XML配置方式进行AOP开发
基于注解方式进行AOP开发
切面类:
如果使用XML配置方式,需要在文件中使用<aop:config>标签,如:
如果想在通知中获取相关数据,任何通知方法可以将第一个参数定义为<code>org.aspectj.lang.JoinPoint</code>类型 (环绕通知需要定义第一个参数为<code>ProceedingJoinPoint</code>类型, 它是 <code>JoinPoint</code> 的一个子类)。<code>JoinPoint</code> 接口提供了一系列有用的方法,比如 <code>getArgs()</code>(返回方法参数)、 <code>getThis()</code>(返回代理对象)、<code>getTarget()</code>(返回目标)、 <code>getSignature()</code>(返回正在被通知的方法签名)和 <code>toString()</code> (打印出正在被通知的方法的有用信息)。
基于注解的方式除了在配置文件中引入aop的命名空间以外,还需要打开自动代理:
<aop:aspectj-autoproxy/>
这个标签将启用Spring对@AspectJ的支持,配置文件里面只需要声明切面对象和目标对象就行了,在类上标注@Aspect注解用以声明切面,然后在切面的方法上面标注通知或者切入点.
定义切入点的几点注意:
* 切入点使用方法定义的形式出现
* 方法的定义
* 方法的修饰符private修饰
* 方法的返回值类型是void
* 方法的名称自定义
* 方法没有参数
* 方法有方法体,方法体为空
在方法上使用@Pointcut定义切入点,如:
切入点表达式写法:
* 切入点表达式的写法
* execution(主要)表示匹配方法执行的连接点
* 例如: * com.itcast.service..*.save*(..))
* 1 "*" 表示方法的返回类型任意
* 2 com.itcast.service..* 表示service包及其子包中所有的类
* 3 .save* 表示类中所有以save开头的方法
* 4 (..) 表示参数是任意数量
定义通知:
事务管理
仅用四个词解释事务
atomic(原子性):要么都发生,要么都不发生。
consistent(一致性):数据应该不被破坏。
Isolate(隔离性):用户间操作不相混淆
Durable(持久性):永久保存,例如保存到数据库中等
Spring提供了两种事务管理方式:
编程序事务管理
声明式事务管理
编写程序式的事务管理可以清楚的定义事务的边界,可以实现细粒度的事务控制,比如可以通过程序代码来控制你的事务何时开始,何时结束等,与下面的声明式事务管理相比,它可以实现细粒度的事务控制。
如果并不需要细粒度的事务控制,可以使用声明式事务,在Spring中,只需要在Spring配置文件中做一些配置,即可将操作纳入到事务管理中,解除了和代码的耦合,这是对应用代码影响最小的选择,从这一点再次验证了Spring关于AOP的概念。当不需要事务管理的时候,可以直接从Spring配置文件中移除该设置.需要引入用于事务管理的命名空间(tx).
Spring并没有直接管理事务,而是将事务的管理委托给其他的事务管理器实现.
Spring支持的事务管理器:
org.springframework.jdbc.datasource.DataSourceTransactionManager (在单一的JDBC Datasource中的管理事务)
org.springframework.orm.hibernate3.HibernateTransactionManager (当持久化机制是hibernate时,用它来管理事务)
org.springframework.jdo.JdoTransactionManager (当持久化机制是Jdo时,用它来管理事务)
org.springframework.transaction.jta.JtaTransactionManager (使用一个JTA实现来管理事务。在一个事务跨越多个资源时必须使用)
org.springframework.orm.ojb.PersistenceBrokerTransactionManager (当apache的ojb用作持久化机制时,用它来管理事务)
基于XML文件配置事务管理器:
配置完事务管理器后,再常规的配置Bean注入对象.默认只有运行时异常才将导致事务回滚.
基于注解配置事务管理器:
XML配置文件中只需要声明事务管理器,而不需要给它"灵魂",因为"灵魂"是由注解注入,所以需要注解解析器的支持:
<tx:annotation-driven transaction-manager="txManager"/>
注册对事务注解进行解析的处理器,将注解与事务管理器关联起来即可.
小记:三大框架中最难的当属三大框架的整合,本文只是简单的将Spring的一些常见配置记下,诸如SpringMVC也不错,和StrutsMVC只是封装的不一样.Spring强大的声明式事务管理,常被用以业务层的封装.