###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.
-
- 使用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。你的dao需要extend这个类,然后通过调用这个类的getHibernateTemplate方法来得到HibernateTemplate对象,从而能够使用HibernateTemplate对象里的方法like save/update/delete/query等方法来操作数据库,对于HibernateDaoSupport里的sessionFactory方法,它是用来接收注入sessionFactory的。这种方法我们的代码也不用管理session的开启和关闭,因为spring的HibernateDaoSupport最终会调用HibernateTemplate对象,而HibernateTemplate已经帮我们做了封装。
-
- 对于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