### 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");
<aop:aspect ref="audience">(此时便指明是一个aspect)
<aop:before method="takeSeats" (指明了advice要做什么,以及在什么时候做
</aop:aspect>
pf.perform();======>在执行此方法之前执行takeSeats方法。
在AOP中有几个概念:
— 方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现。
— 连接点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
— 通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。
— 切入点(Pointcut):指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点,例如,使用正则表达式。
所以“<aop:aspect>”实际上是定义横切逻辑,就是在连接点上做什么,“<aop:advisor>”则定义了在哪些连接点应用什么<aop:aspect>。Spring这样做的好处就是可以让多个横切逻辑(即<aop:aspect>定义的)多次使用,提供可重用性。
implement-interface="interfaces.Contestant" default-impl="beans.GraciousContestant"/>
</aop:aspect>
// pf.perform();
pf.receiveAward();
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.*****");
}
***********************************************************************************
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):返回与指定的名字绑定的对象
<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>
-
- 使用HibernateTemplate的例子:
-
- <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
- <property name="sessionFactory" ref="sessionFactory"></property>
- </bean>
- 在程序中直接用就可以了,如下
- @Component("u")
- public class UserDaoImpl_HibernateTemplate implements UserDao {
- private HibernateTemplate hibernateTemplate;
- @Resource
- public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
- this.hibernateTemplate = hibernateTemplate;
- }
- public void save(User user) {
- hibernateTemplate.save(user);
- }
- }
-
- 对于HibernateDaoSupport:
-
- public final void setSessionFactory(SessionFactory sessionFactory)
- public final SessionFactory getSessionFactory()
- public final void setHibernateTemplate(HibernateTemplate hibernateTemplate)
- public final HibernateTemplate getHibernateTemplate()
- 从它类里的方法可以知道,在使用的时候只需要将sessionFactory注入给HibernateDaoSupport,然后就可以通过getHibernateTemplate
- 来获得HibernateTemplate,这样就可以使用HibernateTemplate了,就和上面使用HibernateTemplate的一样的
- (显然这有点绕了一点弯,个人感觉还是直接使用HibernateTemplate就可以了,不过根据个人喜好或项目的需求而定)
- 下面是实现设计的方法:
- service:
- public class UserService {
- private UserDao userDao;
- public void setUserDao(UserDao userDao) {
- this.userDao = userDao;
- }
- public void add(User user){
- userDao.save(user);
- }
- dao:
- public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
- public void save(User user) {
- this.getHibernateTemplate().save(user);
- }
- }
- bean.xml:
- <bean id="userService" class="com.zcy.service.UserService">
- <property name="userDao" ref="userDao"></property>
- </bean>
- <bean id="userDao" class="com.zcy.dao.impl.UserDaoImpl">
- <property name="sessionFactory" ref="sessionFactory"></property>
- </bean>
- 这里的sessionFacotry注入不是给类UserDaoImpl 的,而是给继承HibernateDaoSupport类的sessionFactory,使用HibernateDaoSupport好处就是我们不再需要关心关闭、
- 是否连接成功等问题(在使用spring封装的这些类,即HibernateDaoSupport,HibernateTemplate,jdbcTemplate,都不需要关心是否关闭,是否连接的问题,因为spring已这些操作封装给注入好了),
- 这样用起来很方便。但是这个不好就是java只支持单继承,所以唯一的继承给了HibernateDaoSupport有点可惜。
- 另外注意的是因为HibernateDaoSupport已经有setSessionFactory(SessionFactory sessionFactory)这个方法了,所以在UserDaoImpl 的类里就不需要写了,
- 并且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来解决.
- <bean id="sessionFactory" class="org.springframework.orm.hibernate3.
- LocalSessionFactoryBean">
- <!-- the properties setting-->
- </bean>
- <bean id="accountRepo" class="com.mycompany.HibernateAccountRepository">
- <constructor-arg ref="sessionFactory"></constructor-arg>
- </bean>
- <bean class="org.springframework.dao.annotation. PersistenceExceptionTranslationPostProcessor"/>
- @Repository
- public class HibernateAccountRepository implements AccountRepository {
- private SessionFactory factory;
- public HibernateAccountRepository(SessionFactory factory) {
- this.factory = factory;
- }
- public Account loadAccount(String username) {
- return (Account)factory.getCurrentSession()
- .createQuery("from Account acc where acc.name = :name")
- .setParameter("name", "thethirdpart").uniqueResult();
- }
- }
- reference : page 168
- http://melin.iteye.com/blog/123555
- http://javaeedevelop.iteye.com/blog/1483231