Spring学习笔记

来源:互联网 发布:域名历史记录查询 编辑:程序博客网 时间:2024/05/01 11:21

一、Spring简介

    1、Spring是一个开源的控制反转(Inversionof Control ,IoC)和面向切面(AOP)的容器框架.它的主要目得是简化企业开发

     控制反转:所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转。

  依赖注入:在运行期,由外部容器动态地将依赖对象注入到组件中。

public class PersonServiceBean {     private PersonDao personDao ;    //通过构造器参数,让容器把创建好的依赖对象注入进PersonServiceBean,当然也可以使用setter方法进行注入。     public PersonServiceBean(PersonDao personDao){         this.personDao=personDao;     }      public void save(Person person){            personDao.save(person);     }}

二、Spring优点

   1、降低组件之间的耦合度,实现软件各层之间的解耦。使Controller----Service----DAO 各层之间更加解耦层次清晰。

   2、可以使用容器提供的众多服务,如:事务管理服务、消息服务等等。当我们使用容器管理事务时,开发人员就不再需要手工

控制事务.也不需处理复杂的事务传播。

   3、容器提供单例模式支持,开发人员不再需要自己编写实现代码。

   4、容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能。

   5、容器提供的众多辅作类,使用这些类能够加快应用的开发,如:JdbcTemplateHibernateTemplate

   6、Spring对于主流的应用框架提供了集成支持,如:集成HibernateJPAStruts等,这样更便于应用的开发。

三、Spring开发

   1、框架使用的最少jar包

      dist\spring.jar

      lib\jakarta-commons\commons-logging.jar

      如果使用了切面编程(AOP),还需要下列jar文件

      lib/aspectj/aspectjweaver.jar和aspectjrt.jar

      lib/cglib/cglib-nodep-2.1_3.jar

      如果使用了JSR-250中的注解,@Resource/@PostConstruct/@PreDestroy,还需要下列jar文件

      lib\j2ee\common-annotations.jar

   2、Spring的配置文件,配置文件的取名可以任意,文件可以存放在任何目录下,但考虑到通用性,一般放在类路径下。

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">.....</beans>

   3、实例化Spring容器一般有多种方法

方法一:在类路径下寻找配置文件来实例化容器

ApplicationContextctx =newClassPathXmlApplicationContext(new String[]{"beans.xml"});


方法二:在文件系统下寻找配置文件来实例化容器

ApplicationContextctx =newFileSystemXmlApplicationContext(new String[]{“d:\\beans.xml“});


4、从容器中得到bean实例,当spring容器启动后,因为spring容器可以管理bean对象的创建,销毁等生命周期,所以我们只需从容器直接获取Bean对象就行,而不用编写一句代码来创建bean对象。从容器获取bean对象的代码如下

ApplicationContext ctx =new ClassPathXmlApplicationContext(“beans.xml”);

OrderService service = (OrderService)ctx.getBean("personService");

   5、指定bean的初始化方法和销毁方法

<bean id="xxx"class="cn.itcast.OrderServiceBean"init-method="init"destroy-method="destroy"/>

init方法的执行时机时bean被创建之后紧接着执行init方法

destroy方法执行的时机框架关闭时执行

    6、注入依赖对象

基本类型对象注入:

<bean id="orderService" class="cn.itcast.service.OrderServiceBean">

  <constructor-arg index=“0” type=“java.lang.String” value=“xxx”/>//构造器注入

  <property name=“name” value=“zhao“/>//属性setter方法注入

</bean>

注入其他bean

方式一

<bean id="orderDao" class="cn.itcast.service.OrderDaoBean"/>

<bean id="orderService" class="cn.itcast.service.OrderServiceBean">

        <property name="orderDao" ref="orderDao"/>

</bean>

方式二

<bean id="orderService" class="cn.itcast.service.OrderServiceBean">

      <property name="orderDao">

            <bean  class="cn.itcast.service.OrderDaoBean"/>

     </property>

</bean>


    7、 集合类型的装配:

public class OrderServiceBean {private Set<String> sets = new HashSet<String>();private List<String> lists = new ArrayList<String>();private Properties properties = new Properties();private Map<String, String> maps = new HashMap<String, String>();        ....//这里省略属性的getter和setter方法}

配置文件中配置

<bean id="order" class="cn.itcast.service.OrderServiceBean">    <property name="lists">          <list><value>lihuoming</value>         </list>      </property>      <property name="sets">         <set>            <value>set</value>        </set>      </property>     <property name="maps">        <map>            <entry key="lihuoming" value="28"/>       </map>     </property>     <property name="properties">        <props><prop key="12">sss</prop>       </props>      </property></bean>

    8、依赖注入

          使用构造器注入

          使用属性setter方法注入

          使用Field注入(用于注解方式)

注入依赖对象可以采用手工装配或自动装配,这里主要说明手工装配,手工装配有两种方式第一就是在bean文件中配置,第二种就是使用注解的方式。

在xml配置文件中,通过在bean节点下配置,如

<bean id="orderService" class="cn.itcast.service.OrderServiceBean">

  <constructor-arg index=“0” type=“java.lang.String” value=“xxx”/>//构造器注入

  <propert yname=“name” value=“zhao”/>//属性setter方法注入

</bean>

在java代码中使用@Autowired或@Resource注解方式进行装配。但我们需要在xml配置文件中配置以下信息:

<beans xmlns="http://www.springframework.org/schema/beans"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      xmlns:context="http://www.springframework.org/schema/context"

      xsi:schemaLocation="http://www.springframework.org/schema/beans

          http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

           http://www.springframework.org/schema/context

          http://www.springframework.org/schema/context/spring-context-2.5.xsd">

          <context:annotation-config/>//用于注册进行解析的处理器

</beans>

这个配置隐式注册了多个对注释进行解析处理的处理器:AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor

注: @Resource注解在spring安装目录的lib\j2ee\common-annotations.jar

java代码中使用@Autowired@Resource注解方式进行装配,这两个注解的区别是

Autowired默认按类型装配,@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。

@Autowired     private PersonDao  personDao;//用于字段上    @Autowired    public void setOrderDao(OrderDao orderDao) {//用于属性的setter方法上        this.orderDao = orderDao;    }

@Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。

如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下:

    @Autowired @Qualifier("personDaoBean")

   private PersonDao personDao;


@Resource注解和@Autowired一样,也可以标注在字段或属性的setter方法上,但它默认按名称装配。名称可以通过@Resource的name属性指定,如果没有指定name属

性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。

  @Resource(name=“personDaoBean”)

  private PersonDao personDao;//用于字段上

  @Resource注解可以用到属性的setXxx()方法上

注意:如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装

配了。

  9、通过在classpath自动扫描方式把组件纳入Spring容器中管理

   前面的例子我们都是使用XML的bean定义来配置组件。在一个稍大的项目中,通常会有上百个组件,如果这些这组件采用xml的bean定义来配置,显然会增加配置文件的体

积,查找及维护起来也不太方便。spring2.5为我们引入了组件自动扫描机制,他可以在类路径底下寻找标注了@Component、@Service、@Controller、@Repository注解的

类,并把这些类纳入进spring容器中管理。它的作用和在xml文件中使用bean节点配置组件是一样的要使用自动扫描机制,我们需要打开以下配置信息:

<beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:context="http://www.springframework.org/schema/context"       xsi:schemaLocation="http://www.springframework.org/schema/beans           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-2.5.xsd">          <context:component-scan base-package="cn.itcast"/>//设置要扫描的类,并注册解析的处理器可以省去<context:annotation-config/>标签</beans>
其中base-package为需要扫描的包(含子包)。

@Service("personService")@Scope("prototype")      public class PersonService {...}

@Service用于标注业务层组件、 @Controller用于标注控制层组件(如struts中的action)、@Repository用于标注数据访问组件,即DAO组件。而@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。@Scope可以标注bean范围,@PostConstruct标注bean实例化后紧接着执行的方法,@PreDestroy标注bean在销毁之前执行的方法


四、AOP编程

    1、aop编程中的概念

Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面横切性关注点的抽象.

joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点,实际上joinpoint还可以

是field或类构造器)

Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义.

Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知

Target(目标对象):代理的目标对象

Weave(织入):指将aspects应用到target对象并导致proxy对象创建的过程称为织入.

Introduction(引入):在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field.


2、要进行AOP编程,首先我们要在spring的配置文件中引入aop命名空间:

<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"

       xsi:schemaLocation="http://www.springframework.org/schema/beans

          http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

          http://www.springframework.org/schema/aop

          http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

</beans>

Spring提供了两种切面声明方式,基于xml配置的方式声明切面和基于注解的方式声明切面。

方式一:基于注解的方式声明切面

首先启动对@AspectJ注解的支持(蓝色部分):

<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"

       xsi:schemaLocation="http://www.springframework.org/schema/beans

          http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

          http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

   <aop:aspectj-autoproxy/>

  <beanid="orderservice"class="cn.itcast.service.OrderServiceBean"/>

  <beanid="log" class="cn.itcast.service.LogPrint"/>

</beans>

@Aspectpublic class LogPrint {@Pointcut("execution(* cn.itcast.service..*.*(..))")private void anyMethod() {}//声明一个切入点@Before("anyMethod() && args(userName)")//定义前置通知public void doAccessCheck(String userName) {}@AfterReturning(pointcut="anyMethod()",returning="revalue")//定义后置通知public void doReturnCheck(String revalue) {}@AfterThrowing(pointcut="anyMethod()", throwing="ex")//定义例外通知(发生异常时执行前置通知、最终通知、异常通知)    public void doExceptionAction(Exception ex) {}@After("anyMethod()")//定义最终通知public void doReleaseAction() {}@Around("anyMethod()")//环绕通知public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {return pjp.proceed();

方式二:基于xml配置方式声明切面

public class LogPrint {public void doAccessCheck() {}定义前置通知public void doReturnCheck() {}定义后置通知    public void doExceptionAction() {}定义例外通知public void doReleaseAction() {}定义最终通知public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {return pjp.proceed();环绕通知}}

xml切面配置

<bean id="orderservice" class="cn.itcast.service.OrderServiceBean"/><bean id="log" class="cn.itcast.service.LogPrint"/><aop:config>  <aop:aspect id="myaop" ref="log">  <aop:pointcut id="mycut" expression="execution(* cn.itcast.service..*.*(..))"/>  <aop:before pointcut-ref="mycut" method="doAccessCheck"/>  <aop:after-returning pointcut-ref="mycut" method="doReturnCheck "/>  <aop:after-throwing pointcut-ref="mycut" method="doExceptionAction"/>  <aop:after pointcut-ref="mycut" method=“doReleaseAction"/>  <aop:around pointcut-ref="mycut" method="doBasicProfiling"/>  </aop:aspect></aop:config>

拦截方法的限定条件:

execution(* cn.itcast.service..*.*(..))表示要拦截的限定条件,第一个*表示拦截方法的返回值类型(!viod)表示返回不能为空类型,包名后面的..表示本包或其子包中的所有类后面两个*分别表示类名和方法名(..)表示可以有任意个参数(java.lang.String,..)表示要拦截方法的第一个参数为String类型

五、Spring事物管理

1、配置事务:配置事务时,需要在xml配置文件中引入用于声明事务的tx命名空间(见下页),事务的配置方式有两种:注解方式和基于XML配置方式。
spring配置文件中引入用于声明事务的tx命名空间

<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:context="http://www.springframework.org/schema/context"

       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.5.xsd

          http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.5.xsd

          http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.5.xsd

          http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd">

</beans>

2、配置数据源

<context:property-placeholder location=“jdbc.properties”/>  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">   <property name="driverClassName" value="${driverClassName}"/>    <property name="url" value="${url}"/>    <property name="username" value="${username}"/>    <property name="password" value="${password}"/>     <!-- 连接池启动时的初始值 --> <property name="initialSize" value="${initialSize}"/> <!-- 连接池的最大值 --> <property name="maxActive" value="${maxActive}"/> <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 --> <property name="maxIdle" value="${maxIdle}"/> <!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 --> <property name="minIdle" value="${minIdle}"/>  </bean>

3、采用注解的方式配置事物

<!– 采用spring的事务管理器  -->

<bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

 </bean>

<!– 采用@Transactional注解方式使用事务  -->

  <tx:annotation-driven transaction-manager="txManager"/>

当遇到运行期例外RuntimeException(unckeck)默认回滚

@Transactional(noRollbackFor=RuntimeException.class)//设置RuntimeException例外不发生回滚

当遇到Exception例外(check)默认不回滚

@Transactional(rollbackFor=Exception.class)//设置Exception也回滚

当执行查找操作时我们不需要开启事务

@Transactional(propagation=Propagation.NOT_SUPPORTED)//设置不需要打开事务

当只读时做成一个只读事务,可以提高效率

@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

@Service @Transactional

public class PersonServiceBeanimplements PersonService{

}

4、基于xml的方式配置事物

<bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource"ref="dataSource"/>

</bean>

<aop:config>

    <aop:pointcutid="transactionPointcut"expression="execution(*cn.itcast.service..*.*(..))"/>

    <aop:advisoradvice-ref="txAdvice"pointcut-ref="transactionPointcut"/>

</aop:config>

<tx:adviceid="txAdvice"transaction-manager="txManager">

    <tx:attributes>

      <tx:methodname="get*" read-only="true"propagation="NOT_SUPPORTED"/>

      <tx:methodname="*"/>

    </tx:attributes>

</tx:advice>

六、事物

1、事物传播属性:

REQUIRED:业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新

的事务。

NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,

该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行。

REQUIRESNEW:属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务

会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行。

MANDATORY:该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在没有事务的环

境下调用,容器就会抛出例外。

SUPPORTS:这一事务属性表明,如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分。如果业务方法在事务范围外

被调用,则方法在没有事务的环境下执行。

Never:指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任

何事务,才能正常执行。

NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中.如果没有活动事务,则按REQUIRED属性执行.它使用了一个单独的

事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事

务管理器起效

2、事物的隔离级别

Read Uncommited:读未提交数据(会出现脏读,不可重复读和幻读)。
Read Commited:读已提交数据(会出现不可重复读和幻读)
Repeatable Read:可重复读(会出现幻读)
Serializable:串行化

脏读:一个事务读取到另一事务未提交的更新新据。

不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同。换句话说就是,后续读取可以读到另一事务已提交的更新数据。相反,“可重复读”在

同一事务中多次读取数据时,能够保证所读数据一样,也就是,后续读取不能读到另一事务已提交的更新数据。

幻读:一个事务读取到另一事务已提交的insert数据。



0 0
原创粉丝点击