Spring笔记

来源:互联网 发布:建筑ar软件下载 编辑:程序博客网 时间:2024/05/17 00:59

掌握用法 不断实践 反复总结

课程内容

1. 面向接口(抽象)编程的概念与好处

2. IOC/DI的概念与好处

a) inversion of control

b) dependency injection

3. AOP的概念与好处

4. Spring简介

5. Spring应用IOC/DI(重要)

a) xml

b) annotation

6. Spring应用AOP(重要)

a) xml

b) annotation

7. Struts2.3.28 + Spring2.5.6 + Hibernate3.3.2整合(重要)

a) opensessionInviewfilter (延迟加载数据的访问异常)(记住,解决什么问题,怎么解决)

8. Spring JDBC

面向接口编程(面向抽象编程)

1. 场景:用户添加

2. 好处:灵活

什么是IOC(控制反转)(别名:DI依赖注入),有什么好处

1. 把自己new的东西改为由容器提供

a) 初始化具体值

b) 装配

2. 好处:灵活装配

Spring简介

1. 环境搭建

2. IOC容器

a) 实例化具体bean

b) 动态装配

3. AOP支持

a) 安全检查

b) 管理transaction

Spring IOC配置与应用

1. FAQ:不给提示:

a) window – preferences – myeclipse – xml – xml catalog

b) User Specified Entries – add

i. Location:  spring-framework-2.5.6\dist\resources\spring-beans-2.5.xsd

ii. URI:    spring-framework-2.5.6/dist/resources/spring-beans-2.5.xsd

iii. Key Type: Schema Location

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

 

 

2. 注入类型

c) setter(重要)调用了setXXX()方法

<bean id="userbiz" class="com..service.UserBiz">

<property name="userDao" >

<ref bean="dao"/>

</property>

</bean>

d) 构造方法(可以忘记)

       public class UserBiz {

    

     public UserBiz(UserDao userDao) {

super();

this.userDao = userDao;

    }

省掉其他。。。。

}

        <bean id="userbiz" class="com..service.UserBiz">

<constructor-arg ref="dao"></constructor-arg>

    </bean>

     如果构造函数中有多个参数

<constructor-arg index="0" ref="dao"></constructor-arg>

 

e) 接口注入(可以忘记)

 

2. id vs. name

a) Id\name都行

b) name可以用特殊字符

 <bean name="u" class="com.demo.dao.impl.UserDAOImpl">

      </bean>

    <bean id="userService" class="com.demo.service.UserService">

   <!--

  <property name="userDAO"ref="u" />

   -->

    <constructor-arg>

     <ref bean="u"/>

    </constructor-arg>

   </bean>

3. 简单属性的注入 API3.3.2.1.

a) <property name=… value=….> 给一些定义好了的数据类型赋值

比如:int string 很少用到 (数据库的urldriver,uid,pwd会用到)

4. <bean 中的scope属性<bean的生命范围>API3.4

    Request\Session只有SpringWeb Framework结合时才会起作用,比如SpringStruts结合时才配,但是很少配、、、、

a) singleton单例(默认为Singleton

 在每个Sprign IOC容器中一个Bean定义对应一个对象实例

b) proptotype每次创建新的对象

如果beanaction,scope设置为proptotype(官方推荐)

5. 集合注入API3.3.2.4

a) 很少用,不重要!参考程序

6. 自动装配

a) byName

<beans>

    <bean name="userDAO1" class="com.demo.dao.impl.UserDAOImpl">

     <property name="daoId" value="1"></property>

   </bean>

   <bean name="userDAO2" class="com.demo.dao.impl.UserDAOImpl">

      <property name="daoId" value="2"></property>

   </bean>

    <bean id="userService" class="com.demo.service.UserService" scope="prototype" autowire="byName">

  </bean>

</beans>

根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,

并将其与属性自动装配。例如UserService里面有userDAO1属性,在装配时就会查找与userDAO1属性相同的Bean,即 <bean name="userDAO1" class="com.demo.dao.impl.UserDAOImpl">  <propertyname="daoId" value="1"></property></bean>,所以当System.out.println(service.getUserDAO1)时,结果为daoId=1。

 

c)、byType

  如果容器中存在一个与指定类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType类型自动装配。

  byType时,如果按照上面的形式写,将出错,因为userDAO1userDAO2类型一样。

d)、constructor (了解): 与ByType方式类似,不同之处在于它应用于构造器参数,如果在容器中没有找到与构造器参数类型一致的bean,那么将抛出异常、、、

d)、如果所有的bean都用同一种,可以使用beans的属性:default-autowire

 

7. 生命周期

a) lazy-init (不重要)

  <bean id="u" class="com.demo.dao.impl.UserDAOImpl"  lazy-init=true>

  </bean>

如果不加 lazy-init=true,只要容器一初始化,也就是ClassPathXmlApplicationContext 一new出来,bean里面的所有class都会初始化、、加上之后如果Context初始化,class就不会初始化,而是用到时初始化、、、

<beans default-lazy-init=”true”>

b) init-method destroy-method不要和prototype一起用(了解)

8. Annotation第一步:

a) 修改xml文件,参考文档<context:annotation-config/>

9. @Autowired

a) 默认按类型by type

  public class UserBiz {

private UserDao uDao;

 @Autowired

public void setuDao(UserDao uDao) {

this.uDao = uDao;

}

}

 

b) 如果想用byName,使用@Qulifier

 <bean id="admin" class="com.demo.dao.impl.UserDao_admin"></bean>       

    <bean id="d" class="com.demo.dao.impl.UserDao_domestic"></bean>

    <bean id="ubiz" class="com.demo.service.UserBiz" init-method="init" destroy-method="destroy">

 

</bean>

 

    @Autowired

public void setuDao(@Qualifier("d") UserDao uDao) {

this.uDao = uDao;

}

@Autowired(required=false) required=false表示注入该对象不是必须的,在运行报错不一样

c) 写在private field(不建议,破坏封装)

d) 如果写在set上,@qualifier需要写在参数上

10. @Resource(重要)

a) 加入:j2ee/common-annotations.jar(3.1不需要)

b) 默认按名称,名称找不到,按类型

c) 可以指定特定名称

d) 推荐使用

e) 不足:如果没有源码,就无法运用annotation,只能使用xml

11. @Component @Service @Controller @Repository(2.5.6目前4个注解无区别)

a) 初始化的名字默认为类名首字母小写

b) 可以指定初始化bean的名字

c) 1.在配置文件中添加

<context:component-scan base-package="com.demo"></context:component-scan>

就不需要添加beanspring扫描器会在指定的包下自动扫描

2.在类前面添加@Component(对应spring容器中的beanbeanid默认为类名(首字母小写))

也可以指定名字如下:   @Component("admin")

3.UserBiz: 

@Resource(name="admin")

public void setuDao( UserDao uDao) {

this.uDao = uDao;

}

   @Component("ubiz")

public class UserBiz {}

测试类:

ApplicationContext context=new  ClassPathXmlApplicationContext("applicationContext.xml");

    UserBiz userBiz= (UserBiz) context.getBean("ubiz");

     userBiz.save();

12. @Scope  对应xmlbean的生命范围@Scope("prototype")

13. @PostConstruct = init-method; @PreDestroy = destroy-method;

什么是AOP 底层是使用jdk动态代理

1. 面向切面编程Aspect-Oriented-Programming

2. AOP是什么

AOPAspect-Oriented Programming),面向切面编程,看着是跟OOP(面向对象编程)挺相近的,但实际上又有什么区别呢?OOP具有封装,继承,多态等东西来定义从上到下这种层次关系,但要想实现从左到右的关系的话就开始有点水土不服了,例如用户的权限控制,操作日志等,这些与我们要实现的核心功能不大有关系的东西散布在我们代码的周边,显示十分不好看。于是我们引入了AOP的模式。

  

 我们通常在实现一个页面逻辑的时候,通常伴随着操作日志,安全监测,事务处理等几个逻辑,在实现逻辑的时候都要写一大堆这种代码。而AOP就是将这些与主体业务无关,但又有为业务提供服务的逻辑代码封装起来,降低模块之间的耦合度。如图所示中的圆柱体好比如我们的业务流程,aop代表的是那个横向的操作,俗称切面编程。或许上面的这些理论有点头疼,对于AOP我的大体理解是:将那些与业务核心不大相关的杂七杂八的东西独立开,每次实现了业务核心之前或之后,调用一下对应的方法。 

二 最基本的例子

  AOP这种切面编程能干很多事情,例如验证登陆,权限,性能检测,错误信息记录等等,AOP的目的就是将这些东西分离开来,让开发人员专注与核心关注点,下面用到一个简单的验证身份的例子。

  在登陆的时候,我们简单的将用户信息放置于session["User"]中,通常在实现一些关键操作的时候,都会记录用户的信息,所以每次都要判断一下session是否过期,但这动作应该由AOP来做

 

a) 是对面向对象的思维方式的有力补充

b) 我们在两个类中,可能都需要在每个方法中做日志。按面向对象的设计方法,我们就必须在两个类的方法中都加入日志的内容。也许他们是完全相同的,但就是因为面向对象的设计让类与类之间无法联系,而不能将这些重复的代码统一起来。 也许有人会说,那好办啊,我们可以将这段代码写在一个独立的类独立的方法里,然后再在这两个类中调用。但是,这样一来,这两个类跟我们上面提到的独立的类就有耦合了,它的改变会影响这两个类。那么,有没有什么办法,能让我们在需要的时候,随意地加入代码呢?这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程

c) Filter

d) Struts2interceptor

Spring AOP的底层实现技术---

http://www.cnblogs.com/luotaoyeah/p/3778183.html

http://www.51cto.com/specbook/223/39480.htm

 

3. 概念:(了解)

a) JoinPoint  释意:切面与原方法交接点 即 切入点

b) PointCut  释意:切入点集合

c) Aspect(切面)释意:可理解为代理类前说明

d) Advice 释意:可理解为代理方法前说明 例如@Before\@After加在切入点上的建议

e) Target  释意:被代理对象 被织入对象

f) Weave  释意:织入

Spring AOP配置与应用API6.2.3.4.

1. 两种方式:

a) 使用Annotation

b) 使用xml

2. Annotation

a) 加上对应的xsd文件spring-aop.xsd

b) beans.xml <aop:aspectj-autoproxy/>

         <!-- 自动产生代理可以使用aspectj注解的方式定义一个Spring-aop -->

需要在头部加  xmlns:aop="http://www.springframework.org/schema/aop"

   以及xsi:schemaLocation="

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

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

还需要在Preferences --->xml Catalog引入spring-aop-2.5.xsd

     Aspectj是一个面向切面的框架,专门用来实现代理的框架.它可以让切面在方法前或属性初始化前或类加载之后,或异常产生之后....或那些方法我需要添加,那些方法需要过滤不要加。。。spring使用了它.

<aop:aspectj-autoproxy />能让srping使用注解的方式实现aop

c) 此时就可以解析对应的Annotation

d) 建立我们的拦截类

e) 用@Aspect注解这个类

    @Aspect

@Component

public class LogInterceptor {

@Pointcut("execution(public * com.demo.service..*.add(..))")(掌握这一种OK)

public void myMethod(){};

    @Before("myMethod()")(在指定方法执行之前执行的方法)

public void before() {

System.out.println("method before");

}

@Around("myMethod()")

public void aroundMethod(ProceedingJoinPoint pjp)throws Throwable {

System.out.println("method around start");

pjp.proceed();

System.out.println("method around end");

}

}

f) 建立处理方法

g) 用@Before来注解方法

h) 写明白切入点(execution …….

i) 让spring对我们的拦截器类进行管理@Component

3. 常见的Annotation:

a) @Pointcut 切入点声明 以供其他方法使用 , 例子如下:

 

@Aspect

@Component

public class LogInterceptor {

@Pointcut("execution(public * com.demo.dao..*.*(..))")

public void myMethod(){}

 

@Around("myMethod()")

public void before(ProceedingJoinPoint pjp)throws Throwable{

System.out.println("method before");

pjp.proceed();

}

@AfterReturning("myMethod()")

public void afterReturning()throws Throwable{

System.out.println("method afterReturning");

}

@After("myMethod()")

public void afterFinily()throws Throwable{

System.out.println("method end");

}

}

 

b) @Before 发放执行之前织入

c) @AfterReturning 方法正常执行完返回之后织入(无异常)

d) @AfterThrowing 方法抛出异常后织入

e) @After 类似异常的finally

f) @Around 环绕 类似filter ,如需继续往下执行则需要像filter中执行FilterChain.doFilter(..)对象一样 执行ProceedingJoinPoint.proceed()方可,例子如下:

@Around("execution(* com.demo.dao..*.*(..))")

public void before(ProceedingJoinPoint pjp)throws Throwable{

System.out.println("method start");

pjp.proceed();//类似FilterChain.doFilter(..)告诉jvm继续向下执行

}

4. 织入点语法

a) void !void

b) 参考文档(* ..

如果 execution(* com.demo.dao..*.*(..))中声明的方法不是接口实现 则无法使用AOP实现动态代理,此时可引入包” cglib-nodep-2.1_3.jar” 后有spring自动将普通类在jvm中编译为接口实现类,从而打到可正常使用AOP的目的.3的版本无需)

5. xml配置AOP 6.3.1

a) 把interceptor对象初始化

b) <aop:config

i. <aop:aspect …..

1. <aop:pointcut

2. <aop:before

例子:

<beanid="logInterceptor"class="com.demo.aop.LogInterceptor"></bean>

<aop:config>

<!-- 配置一个切面 -->

<aop:aspectid="point"ref="logInterceptor">

<!-- 配置切入点,指定切入点表达式-->

<aop:pointcut

expression=

"execution(public * com.demo.service..*.*(..))"

id="myMethod"/>

<!-- 应用前置通知 -->

<aop:beforemethod="before"pointcut-ref="myMethod"/>

<!-- 应用环绕通知 需指定向下进行-->

<aop:aroundmethod="around"pointcut-ref="myMethod"/>

<!-- 应用后通知 -->

<aop:after-returningmethod="afterReturning"

pointcut-ref="myMethod"/>

<!-- 应用抛出异常后通知-->

<aop:after-throwingmethod="afterThrowing"

pointcut-ref="myMethod"/>

<!-- 应用最终通知  -->

<aop:aftermethod="afterFinily"

pointcut="execution(public * om.demo.service..*.*(..))"/>

</aop:aspect>

</aop:config>

动态代理:ProxyINvocationHandler的使用

 

Spring整合Hibernate

1. Spring 指定datasource

a) 参考文档,找dbcp.BasicDataSource

i. c3p0

ii. Dbcp

iii. Spring 里面的commons-dbcp.jarcommons-pool.jar

iv. API3.7.2.1.

        <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

 <!-- PropertyPlaceholderConfigurer占位符属性的 配置-->

    <property name="locations">

        <value>classpath:com/foo/jdbc.properties</value>

    </property>

</bean>

 

<bean id="dataSource" destroy-method="close"

      class="org.apache.commons.dbcp.BasicDataSource">

    <property name="driverClassName" value="${jdbc.driverClassName}"/>

    <property name="url" value="${jdbc.url}"/>

    <property name="username" value="${jdbc.username}"/>

    <property name="password" value="${jdbc.password}"/>

</bean>

 

v. proxool

b) 在DAO或者Service中注入dataSource

c) 在Spring中可以使用PropertyPlaceHolderConfigure来读取Properties文件的内容

 

2. Spring整合Hibernate

a) <bean .. AnnotationSessionFactoryBean>APi 12.2.2

i. <property dataSource

ii. <annotatedClasses

<bean

class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

<property name="locations">

<value>classpath:jdbc.properties</value>

</property>

</bean>

 

<bean id="dataSource" destroy-method="close"

class="org.apache.commons.dbcp.BasicDataSource">

<property name="driverClassName"

value="${jdbc.driverClassName}" />

<property name="url" value="${jdbc.url}" />

<property name="username" value="${jdbc.username}" />

<property name="password" value="${jdbc.password}" />

</bean>

 

<bean id="sessionFactory"

class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">

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

<property name="annotatedClasses">

<list>

<value>com.demo.model.User</value>

<value>com.demo.model.Log</value>

</list>

</property>

<property name="hibernateProperties">

<props>

<prop key="hibernate.dialect">

org.hibernate.dialect.MySQLDialect

</prop>

<prop key="hibernate.show_sql">true</prop>

</props>

</property>

iii.  </bean>

b) 引入hibernate 系列jar

c) User上加Annotation

d) UserDAO或者UserServie注入SessionFactory

e) jar包问题一个一个解决

 

 

3. 声明式的事务管理

a) 事务加在DAO层还是Service层?

b) annotation

i. 加入annotation.xsd

ii. 加入txManager bean

iii. <tx:annotation-driven>

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

须在Xml文件头里加上xsi:schemaLocation="

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

v. 

例如: <bean id="transactionManager"     class="org.springframework.orm.hibernate3.HibernateTransactionManager">

          <property name="sessionFactory">

            <ref bean="sessionFactory" />

          </property>

    </bean>

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

vi. 在需要事务的方法上加:@Transactional,会自动在前后加上关于事务的业务逻辑,开始时就是BeganTransaction(),结尾时是Transaction Commit().如果捕捉到任何的异常,就会自动Rollback(),如果是runTime异常,会自动回滚。。。

vii. 需要注意,Hibernate获得session时要使用SessionFactory.getCurrentSession不能使用OpenSession

c) @Transactional详解

i. 什么时候rollback

1. 运行期异常,非运行期异常不会触发rollback

2. 必须uncheck (没有catch)

3. 不管什么异常,只要你catch了,spring就会放弃管理

4. 事务传播特性:propagation_required

例如: @Transactional(propagation=Propagation.REQUIRED)等同于(@Transactional)

作用,一个方法声明了@Transactional事务后,其内再调用的方法不需要再声明@Transactional.

5. read_only

例如: @Transactional(propagation=Propagation.REQUIRED,readOnly=true)

当方法声明readOnly=true,该方法及其调用的方法内都不执行insert update

d) xml(推荐,可以同时配置好多方法)

i. <bean txmanager

ii. <aop:config

1. <aop:pointcut

2. <aop:advisor pointcut-ref advice-ref

iii. <tx:advice: id transaction-manager =

iv. <property name="packagesToScan">  可定义扫描目标包下所有实体类

例如: <bean id="sessionFactory"

     class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">

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

    <property name="hibernateProperties">

<props>

<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>

<prop key="hibernate.show_sql">true</prop>   

</props>

</property>

<!--

    <property name="annotatedClasses">

    <list>

    <value>com.demo.model.TestUser</value>

    <value>com.demo.model.Log</value>

    </list>

    </property>

     -->

     <!--将参数名称设为packagesToScan可定义扫描目标包下所有实体类 -->

     <property name="packagesToScan">

     <list>

     <value>com.demo.model</value>

     </list>

     </property>

    </bean>

<bean id="transactionManager"

        class="org.springframework.orm.hibernate3.HibernateTransactionManager">

        <property name="sessionFactory">

            <ref bean="sessionFactory" />

        </property>

    </bean>

    

    <aop:config>

        <aop:pointcut

expression="execution(public * com.demo.service..*.*(..))"

id="myServiceMethod" />

        <aop:advisor pointcut-ref="myServiceMethod" advice-ref="txAdvice"/>

    </aop:config>

    

    <tx:advice id="txAdvice" transaction-manager="transactionManager">

        <tx:attributes>

            <tx:method name="save*" propagation="REQUIRED" />

            <tx:method name="add*" propagation="REQUIRED" />

            <tx:method name="update*" propagation="REQUIRED" />

            <tx:method name="del*" propagation="REQUIRED" />

            <tx:method name="cancel*" propagation="REQUIRED" />

            <tx:method name="*" read-only="true" />

        </tx:attributes>

    </tx:advice>

e) HibernateTemplateHibernateCallbackHibernateDaoSupport(不重要)介绍

i. 设计模式:Template Method(模板方法)

ii. Callback:回调/钩子函数

iii. 第一种:(建议)

1. 在spring中初始化HibernateTemplate,注入sessionFactory

<bean id="hibernateTemplate"

class="org.springframework.orm.hibernate3.HibernateTemplate">

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

</bean>

2. DAO里注入HibernateTemplate

private HibernateTemplate hibernateTemplate;

 

@Resource

public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {

this.hibernateTemplate = hibernateTemplate;

}

3. savegetHibernateTemplate.save();

public void save(TestUser testUser) {

hibernateTemplate.save(testUser);

}

iv. 第二种:

1. 从HibernateDaoSupport继承(此方法不好用 可忽略)

2. 必须写在xml文件中,无法使用Annotation,因为set方法在父类中,而且是final

例如:

首先,新建SuperDAOImpl(使用Annotation注入--@Component):

@Component

public class SuperDAOImpl {

private HibernateTemplate hibernateTemplate; //此处定义由spring注入管理

public HibernateTemplate getHibernateTemplate() {

return hibernateTemplate;

}

@Resource

public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {

this.hibernateTemplate = hibernateTemplate;

}

}

此时,xml中必须要有:

<bean id="hibernateTemplate"

class="org.springframework.orm.hibernate3.HibernateTemplate">

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

</bean>

或者,SuperDAOImpl类写成下面代码:

@Component

public class SuperDAOImpl extends HibernateDaoSupport {

@Resource(name="sessionFactory")

public void setSuperHibernateTemplate(SessionFactory sessionFactory) {

super.setSessionFactory(sessionFactory);

}

}

对应的xml中则可省略

<bean id="hibernateTemplate"………部分

只要包含

<bean id="sessionFactory"……..部分即可

 

最后,其他类继承SuperDaoImpl类后便可直接使用HibernateTemplate

@Component("u")

public class UserDAOImpl extends SuperDAOImpl implements UserDAO {

public void save(TestUser testUser) {

this.getHibernateTemplate().save(testUser);

}

}

spring整合hibernate的时候使用packagesToScan属性,可以让spring自动扫描对应包下面的实体类

 

0 0
原创粉丝点击