`

spring 学习笔记 (一)

 
阅读更多
### WILLM: 无论用hibernate Object还是看sql,关键是看是否都使用hibernateTemplate,
如果是,那么他就受事务传播行为而share同一事务,因为HibernateTemplate封装了管理session
的模板代码
###1.我们常用的加载context文件的方法有如下三个:


1、FileSystemXmlApplicationContext

这个方法是从文件绝对路径加载配置文件,
例如:

ApplicationContext   ctx = new   
FileSystemXmlApplicationContext( "G:/Test/applicationcontext.xml ");


如果在参数中写的不是绝对路径,那么方法调用的时候也会默认用绝对路径来找,
我测试的时候发现默认的绝对路径是eclipse所在的路径。

采用绝对路径的话,
程序的灵活性就很差了,所以这个方法一般不推荐。

(如果要使用classpath路径,
需要加入前缀classpath:   )


2、ClassPathXmlApplicationContext

这个方法是从classpath下加载配置文件
(适合于相对路径方式加载),例如:

ApplicationContext   ctx = 
new   ClassPathXmlApplicationContext( "/applicationcontext.xml ");


该方法参数中classpath: 前缀是不需要的,默认就是指项目的classpath路径下面;
这也就是说用ClassPathXmlApplicationContext时默认的根目录是在WEB-INF/classes下面,
而不是项目根目录。这个需要注意!


3、XmlWebApplicationContext

专为web工程定制的方法,
推荐Web项目中使用。=====>在web服务器启动时会加载并解析spring配置文件,同时需要在web.xml中
作出配置
<listener> 
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class> 
</listener> 
<context-param> 
<param-name>contextConfigLocation</param-name> 

<param-value>/WEB-INF/applicationContext.xml</param-value> 
</context-param> 
在代码中可通过Spring提供的Web工具类WebApplicationContextUtils直接获取容器中的Bean
实例并调用其方法
例如:

ServletContext   servletContext   =   
request.getSession().getServletContext();

          
 ApplicationContext   ctx   =  
 WebApplicationContextUtils.getWebApplicationContext(servletContext);
===>这里的实际原理是:ContextLoaderListener 实现了ServletContextListener,
这样当web服务器启动时便会执行它的contextInitialized方法,
在该方法中将会解析参数contextConfigLocation
(CONFIG_LOCATION_PARAM = "contextConfigLocation";)对应的xml,进而创建
WebApplicationContext对象。然后放到一个static的map对象中(ContextLoader类的 line 200
and line 201:
servletContext.setAttribute(WebApplicationContext.
ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
 
 currentContextPerThread.put(Thread.currentThread().
getContextClassLoader(), this.context);
)
,这样整个初始化便完成了,在application中便有一个WebApplicationContext供我们使用了,
也就是说只要我们找的到这个WebApplicationContext 对象context,我们就可以通过这个context
变量调用getBean方法来随意地get到我们的service对象了。
  接下来便是工具类WebApplicationContextUtils 出场,它的作用主要是从那个map中为我们取出
那个WebApplicationContext 对象,进而能够为我们用来getBean对象。
但是我们不想在每个地方都要直接通过WebApplicationContextUtils 来创建ApplicationContext
对象,因为WebApplicationContextUtils.getWebApplicationContext方法需要ServletContext   
对象作为参数的,
ApplicationContext   ctx   =  
 WebApplicationContextUtils.getWebApplicationContext(servletContext);

有的类并没那么容易得到 ServletContext   对象的,所以我们可以在初始化时通过
单例模式使用一次WebApplicationContextUtils的getWebApplicationContext方法来为我们
创建一个单例对象供我们程序的其他地方使用。
  思想跟ContextLoaderListener 差不多,我们可以创建自己的listener来实现
ServletContextListener并覆盖contextInitialized方法,这样当web服务器启动后,我们的
contextInitialized方法将被调用执行,我们可以在那里初始化创建一个static的
WebApplicationContext (ApplicationContext是父接口)对象来为我们的其他程序getBean用,
比如:

当web服务器启动后,它会去解析web.xml,如果我们需要在服务启动以后

做一些初始化,那么可以在web.xml中配置ServeltContextListener

来达到初始化,因为在web应用程序的初始阶段,servlet容器会调用

ServletContextListener对象的contextInitialized()方法。

   public class SunriseWebContextListener implements ServletContextListener{

// @Override
 public void contextDestroyed(ServletContextEvent event) {
  
 }

// @Override
 public void contextInitialized(ServletContextEvent event) {
  SpringConfig.init(event.getServletContext());
  DataManage.getInstance();
 }

}

然后将这个WebContextListener配到web.xml中即可

     <listener>
        <listener-class>com.common.SunriseWebContextListener </listener-class>
    </listener>

在初始化阶段,web容器(如tomcat)将会调用这个 contextInitialized方法,这时如果我们需要Spring的ApplicationContext对象时,

就可以在init方法中实现:

 public class SpringConfig {
 private static ApplicationContext springContext;
 public static void init(ServletContext servletContext) {
  springContext=WebApplicationContextUtils.getWebApplicationContext

(servletContext);
 }
 
 

public static ApplicationContext getSpringContext(){
  return springContext;
 }
}

这样我们就可以通过单例模式得到的ApplicationContext对象springContext来随意地取得所需要的service bean了:

public class DataManage {
 private static DataManage instance;
 private TaskTypeService taskTypeSV=(TaskTypeService) SpringConfig.getSpringContext()
 .getBean("taskTypeService");
 private StageService stageSV=(StageService) SpringConfig.getSpringContext()
 .getBean("stageService");
 private ProjectService projectSV=(ProjectService) SpringConfig.getSpringContext()
 .getBean("projectService");
// private ProjectTypeService projectTypeSV;
 private UserService userSV=(UserService) SpringConfig.getSpringContext()
 .getBean("userService");
 private CategoryService categorySV=(CategoryService) SpringConfig.getSpringContext()
 .getBean("categoryService");

##2.IOC : 对于传统编程来说,当需要一个对象时便要在实体类创建一个对象,IOC 则在spring容器中帮忙创建对象。(IoC就是Inversion of Control,控制反转。在Java开发中,IoC意味着将你设计好的类交给系统去控制,而不是在你的类内部控制。这称为控制反转。)======>简单来说IOC是创建对象交给spring的容器(实际是配置的xml以及用反射机制来完成创建的)负责创建对象的。
    DI:在创建一个bean后,如果该bean的一些属性需要值,不管是普通类型比如是基本类型,string,还是对象类型的属性,我们都可以使用DI在spring配置文件中声明值,通过spring容器将值赋给bean的属性。所以IOC 和DI还是两个不同的概念,IOC指的是通过在spring容器中创建bean,而DI则是可以给这些bean的属性赋值.
IOC和DI的好处: 降低耦合,易于测试,方便将来的维护。
###3. Interface can work hand in hand with the DI to provide loose coupling.
###4.ref bean 和 DI innerBean的区别是,被ref的bean是可以共享的,而innerBean只能injection给一个bean,只能injection一次,是某个bean专有的。
###5.学习Spring In Action英文版之后,突然感觉很多概念比以前容易理解了,另外感觉spring 2.5后spring使用AOP方面方便了好多好多,首先说advice,现在任何一个java class都可以是一个aspect,只要在xml用<aop:aspect来定义就可以了,advice里的方法就是aspect要做什么的,至于什么时候做,现在也不用实现什么接口了,只需要简单实用<aop:before> 便可以轻松地指定在执行切入点之前便执行advice里的方法了,可以说,以前的spring版本里,advice必须要实现一些向methodxxx接口,在一个advice里既指出要做什么同时也指出了什么时候做(before or after or both),现在只用一个简单的bean指定要做什么,然后通过用aop标签<aop:before>指出什么时候做,也就是说在切入点joinpoint之前做还是之后作。而pointcut便是负责撮合advice和joinpoint,现在只要在xml里用aop标签简单指定即可,如例子:
<bean id="audience" class="beans.Audience"/>(此时就是普通的一个bean)
<aop:config>
       <aop:aspect ref="audience">(此时便指明是一个aspect)
        <aop:before method="takeSeats" (指明了advice要做什么,以及在什么时候做
         pointcut="execution(* beans.Juggler.perform(..))"(perform 便是joinpoint,他指出了在什么地方切入advice,而pointcut here用execution撮合了advice和joinpoint。
/>
       </aop:aspect>
Performer pf=(Performer)ac.getBean("duke");
  pf.perform();======>在执行此方法之前执行takeSeats方法。
###spring 中的<aop:advisor>和<aop:aspect>有什么区别?

在AOP中有几个概念:
— 方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现。

— 连接点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。

— 通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。

— 切入点(Pointcut):指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点,例如,使用正则表达式。

所以“<aop:aspect>”实际上是定义横切逻辑,就是在连接点上做什么,“<aop:advisor>”则定义了在哪些连接点应用什么<aop:aspect>。Spring这样做的好处就是可以让多个横切逻辑(即<aop:aspect>定义的)多次使用,提供可重用性。

###Spring AOP introduction
    --------->可以在不用修改原有类和接口的基础上增加方法,在使用时便在客户端强制转换成新的接口类型即可。<aop:declare-parents types-matching="interfaces.Performer+"
       implement-interface="interfaces.Contestant" default-impl="beans.GraciousContestant"/>
       </aop:aspect>
    Contestant pf=(Contestant)ac.getBean("duke");
 // pf.perform();
  pf.receiveAward();
 ###可以使用annotation将一个类标记为aspect,不用再在xml中声明aspect及pointcut等:
@Aspect
public class Audience {
 @Pointcut ("execution(* beans.Juggler.perform(..))")
 public void myPerform(){
  
 }
 @Before("myPerform()")
 public void takeSeats(){
  System.out.println("the audience is taking their seats before the show.*****");
 }
}, 最后在xml里定义autoproxy bean <aop:aspectj-autoproxy/>
###关于datasource和JNDI, datasource是web服务器比如tomcat 创建的对象,所以我们需要在tomcat中配置如在server.xml里配置,它提供了连接数据库的一些信息。如果我们需要在java 中使用该datasource,我们需要用JNDI API去找到datasource对象,进而可以用: http://blog.csdn.net/timesongjie/article/details/7645845
 datasource 提供了一种连接数据库的方式,你可以通过在程序中写连接数据库的代码来实现,但通过 datasource我们就不必要写具体的数据库连接代码了,可以直接从数据源获得数据库连接。datasource里面配置了数据库的连接信息比如 url,user,password,driver等信息。所以说当听到datasource的第一反应应该是一个由服务器比如Tomcat创建的包含了数据连接信息的对象,我们只需使用jndi来获得到该对象便可以使用。而jndi就是一个根据名和对象的捆绑对。
  四、数据源和JNDI的关系:
***********************************************************************************
DataSource对象是由Tomcat提供的,因此不能在程序中采用创建一个实例的方式来生产DataSource对象,而需要采用Java的另一个技术JNDI,来获得DataSource对象的引用。

Tomcat把DataSource作为一种可以配置的JNDI资源来处理。生成DataSource对象的工厂为org.apache.commons.dbcp.BasicDataSourceFactory。

在javax.naming包中提供了Context接口,该接口提供了将对象和名字绑定,以及通过名字检索对象的方法。Context中的主要方法有:
bind(String name,Object object):将对象与一个名字绑定
lookup(String name):返回与指定的名字绑定的对象
 ###Spring Integrate Hibernate.
  1)####如果你不用Hibernate而直接用jdbc的话,可以使用JdbcTemplate或JdbcDaoSupport来进行数据库操作,直接配置SimpleJdbcTemplate的bean或SimpleJdbcDaoSupport的bean并注入相关参数即可.
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
        <constructor-arg ref="dataSource"/>
       </bean>
       <bean id="simpleJdbcTemplateDao" class="utils.SimpleJdbcTemplateDao">
        <property name="simpleJdbcTemplate" ref="jdbcTemplate"/>
       </bean>
       <bean id="sdtextend" class="utils.SimpleJdbcTemplateExtend">
       <property name="dataSource" ref="dataSource"/>
       </bean>
  2)Hibernate最主要的操作接口是session,而sessionFactory是创建session的工厂类,同时它也负责session 的open,close和manage。另外,sessionFactory需要dataSource对象来获取链接数据库的信息。
 3)spring对Hibernate的整合提供了几种使用方法,
   ** 第一种是HibernateTemplate,可以让你的程序和HibernateTemplate一起工作,此时你需要配置HibernateTemplate的bean,并需要在你的dao中注入该bean,HibernateTemplate能够catch Hibernate 的specific的exception,以及他能够管理session的open和close,因为在HibernateTemplate里对session的管理代码进行了封装,比如Opensession。。session.close等。这样HibernateTemplate便能够保证在一个transaction中只有一个session.
  1.  
  2. 使用HibernateTemplate的例子:   
  3.  
  4.   
  5.     <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">  
  6.       <property name="sessionFactory" ref="sessionFactory"></property>  
  7.      </bean>  
  8.   
  9. 在程序中直接用就可以了,如下   
  10.   
  11.     @Component("u")   
  12.     public class UserDaoImpl_HibernateTemplate implements UserDao {   
  13.      private HibernateTemplate  hibernateTemplate;   
  14.        
  15.      @Resource   
  16.      public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {   
  17.       this.hibernateTemplate = hibernateTemplate;   
  18.      }   
  19.        
  20.   
  21.      public void save(User user) {   
  22.       hibernateTemplate.save(user);   
  23.      }   
  24.   
  25.     }   
  ***第二种是提供了HibernateDaoSupport。你的dao需要extend这个类,然后通过调用这个类的getHibernateTemplate方法来得到HibernateTemplate对象,从而能够使用HibernateTemplate对象里的方法like  save/update/delete/query等方法来操作数据库,对于HibernateDaoSupport里的sessionFactory方法,它是用来接收注入sessionFactory的。这种方法我们的代码也不用管理session的开启和关闭,因为spring的HibernateDaoSupport最终会调用HibernateTemplate对象,而HibernateTemplate已经帮我们做了封装。
  1.  
  2. 对于HibernateDaoSupport:   
  3.  
  4.   
  5.     public final void setSessionFactory(SessionFactory sessionFactory)   
  6.   
  7.     public final SessionFactory getSessionFactory()   
  8.   
  9.     public final void setHibernateTemplate(HibernateTemplate hibernateTemplate)   
  10.   
  11.     public final HibernateTemplate getHibernateTemplate()   
  12.   
  13. 从它类里的方法可以知道,在使用的时候只需要将sessionFactory注入给HibernateDaoSupport,然后就可以通过getHibernateTemplate   
  14.   
  15. 来获得HibernateTemplate,这样就可以使用HibernateTemplate了,就和上面使用HibernateTemplate的一样的   
  16.   
  17. (显然这有点绕了一点弯,个人感觉还是直接使用HibernateTemplate就可以了,不过根据个人喜好或项目的需求而定)   
  18.   
  19. 下面是实现设计的方法:   
  20.   
  21. service:   
  22.   
  23.     public class UserService {   
  24.   
  25.      private UserDao userDao;   
  26.        
  27.      public void setUserDao(UserDao userDao) {   
  28.       this.userDao = userDao;   
  29.      }   
  30.         
  31.      public void add(User user){   
  32.         userDao.save(user);   
  33.      }   
  34.   
  35. dao:   
  36.   
  37.     public class UserDaoImpl extends HibernateDaoSupport implements UserDao {   
  38.      public void save(User user) {   
  39.         this.getHibernateTemplate().save(user);   
  40.      }   
  41.   
  42.     }   
  43.   
  44. bean.xml:   
  45.   
  46.     <bean id="userService" class="com.zcy.service.UserService">  
  47.       <property name="userDao" ref="userDao"></property>  
  48.      </bean>  
  49.   
  50.   
  51.      <bean id="userDao" class="com.zcy.dao.impl.UserDaoImpl">  
  52.       <property name="sessionFactory" ref="sessionFactory"></property>  
  53.      </bean>  
  54.   
  55. 这里的sessionFacotry注入不是给类UserDaoImpl 的,而是给继承HibernateDaoSupport类的sessionFactory,使用HibernateDaoSupport好处就是我们不再需要关心关闭、   
  56.   
  57. 是否连接成功等问题(在使用spring封装的这些类,即HibernateDaoSupport,HibernateTemplate,jdbcTemplate,都不需要关心是否关闭,是否连接的问题,因为spring已这些操作封装给注入好了),   
  58.   
  59. 这样用起来很方便。但是这个不好就是java只支持单继承,所以唯一的继承给了HibernateDaoSupport有点可惜。   
  60.   
  61. 另外注意的是因为HibernateDaoSupport已经有setSessionFactory(SessionFactory sessionFactory)这个方法了,所以在UserDaoImpl 的类里就不需要写了,   
  62.   
  63. 并且HibernateDaoSupport的setSessionFactory的方法时final的,所以重写还会报错的。

***第三种是使用Contextual session,因为在Hibernate3后,hibernate可以自己管理session的开启和关闭已及相关的管理,我们不再需要template代码去封装session开关的骨架代码了,也就是说我们可以不用HibernateTemplate的帮忙了,主要把session传到我的dao中,我们便可以直接使用session对象的方法来操作数据库了.至于要处理Hibernate那些specific exception,我们只需要插入一个aspect,使用annotaction的方式来使用那个aspect即可,也就是通过spring的@Repository annotation和post processor-PersistenceExceptionTranslationPostProcessor来解决.

 

  1. <bean id="sessionFactory" class="org.springframework.orm.hibernate3.   
  2. LocalSessionFactoryBean">   
  3. <!-- the properties setting-->   
  4. </bean>   
  5.     
  6. <bean id="accountRepo" class="com.mycompany.HibernateAccountRepository">   
  7. <constructor-arg ref="sessionFactory"></constructor-arg>   
  8. </bean>   
  9. <bean class="org.springframework.dao.annotation. PersistenceExceptionTranslationPostProcessor"/>  

  

  1. @Repository  
  2. public class HibernateAccountRepository implements AccountRepository {   
  3.     
  4. private SessionFactory factory;   
  5.     
  6. public HibernateAccountRepository(SessionFactory factory) {   
  7. this.factory = factory;   
  8. }   
  9.     
  10. public Account loadAccount(String username) {   
  11. return (Account)factory.getCurrentSession()   
  12. .createQuery("from Account acc where acc.name = :name")   
  13. .setParameter("name""thethirdpart").uniqueResult();   
  14. }   
  15. }  
  16. reference : page 168
  17. http://melin.iteye.com/blog/123555
  18. http://javaeedevelop.iteye.com/blog/1483231

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics