什么是框架
在的J2EE开发中,经常会提到“框架”这个词汇,例如Spring,Struts,Webx等等都称之为J2EE开发框架。那么,什么是框架呢?
框架的英文为Framework,带有骨骼,支架的含义。
在软件工程中,框架被定义为整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。
一个框架是一个可复用的设计构件,它规定了应用的体系结构,阐明了整个设计、协作构件之间的依赖关系、责任分配和控制流程,表现为一组抽象类以及其实例之间协作的方法,它为构件复用提供了上下文(Context)关系。
框架是实现了某应用领域通用功能的底层服务。使用这种框架的编程人员可以在一个通用功能已经实现的基础上开始具体的系统开发。框架提供了所有应用期望的默认行为的类集合。具体的应用通过重写子类或组装对象来支持应用专用的行为。
通俗的说,框架是完成是某种应用的半成品,提供了一些常用的工具类和一些基础通用化的组件,可以供开发人员在此基础上,更便捷的完成各自特有的系统。
Spring是一个综合型框架,致力于J2EE应用的各层的解决方案,而不是仅仅专注于某一层的方案。可以说Spring可以作为应用开发的“一站式”选择,并贯穿表现层、业务层及持久层。然而,Spring并不想取代那些已有的框架,它可以与其他框架无缝地整合。
考虑到面向的领域,以及实现编码实现,我们可以将将框架至少分为三类。
第一类是基础类库,主要包含多数项目所需要的类库。(开发人员将其作为一个类库使用,可以简化一些常用的算法逻辑。)
第二类是基础框架,该框架应该整合或者实现J2EE开发所需要的常用功能。(此框架可以为各类WEB项目开发提供基础支持。)
第三类是平台框架,针对于某种特定领域,实现特定领域所需要的常用功能。(这个框架需要实现具体领域的业务的逻辑。并且应该支持各类扩展)
为什么需要整合呢?
使用spring ,主要是使用它的ioc(可以理解成管理bean的一个容器) ,aop(面向切面编程:持久化管理(Persistent)、事务管理(Transaction Management)、安全管理(Security)、日志管理(Logging)和调试管理(Debugging)等) ,jdbcTemplate(封装操作数据库,不用再自己建立关闭连接了,挺方便的。)
当然还有一部分是工作需要, spring的IOC可以降低对象的耦合度,方便用junit做自动化测试.
以上的部分只是自己摘抄的个人理解。
接下来开始真正进入代码的世界,我们来实现一个添加图书和查询图书信息的功能。使用Spring和Hibernate整合
创建实体类:
package cn.books.beans; /** * Created by accp on 2017/3/30. */ public class Book { private Integer id; private String name; private String price; public Book() { } public Book(String name, String price) { this.name = name; this.price = price; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPrice() { return price; } public void setPrice(String price) { this.price = price; } }
小配置:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.books.beans"> <class name="Book" table="Book"> <id name="id"><generator class="native"></generator></id> <property name="name"/> <property name="price"/> </class> </hibernate-mapping>
dao:
package cn.books.dao; import cn.books.beans.Book; /** * Created by accp on 2017/3/30. */ public interface BookDao { int add(Book book); }
dao层的实现(implements):
package cn.books.dao.impl; import cn.books.beans.Book; import cn.books.dao.BookDao; import org.hibernate.SessionFactory; import org.springframework.transaction.annotation.Transactional; import java.io.Serializable; /** * Created by accp on 2017/3/30. */ public class BookDaoImpl implements BookDao { private SessionFactory sessionFactory; @Transactional public int add(Book book) { Serializable count = sessionFactory.getCurrentSession().save(book); return (Integer) count; } public SessionFactory getSessionFactory() { return sessionFactory; } public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } }
biz层(业务逻辑):
package cn.books.biz; import cn.books.beans.Book; /** * Created by accp on 2017/3/30. */ public interface BookBiz { int add(Book book); }
biz的实现层:
package cn.books.biz.impl; import cn.books.beans.Book; import cn.books.biz.BookBiz; import cn.books.dao.BookDao; /** * Created by accp on 2017/3/30. */ public class BookBizImpl implements BookBiz{ private BookDao dao; public int add(Book book) { return dao.add(book); } public BookDao getDao() { return dao; } public void setDao(BookDao dao) { this.dao = dao; } }
这些类创建完成了,接下我们就改配置applicationContext.xml了。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd "> <!--注入jdbc.properties--> <context:property-placeholder location="classpath:jdbcmysql.properties"></context:property-placeholder> <!--数据源--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!--sessionFactory配置--> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="hibernateProperties"> <props> <!--方言--> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <!--获取当前线程中的session--> <prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate5.SpringSessionContext</prop> </props> </property> <!--关联小配置--> <property name="mappingDirectoryLocations" value="classpath:cn/books/beans"></property> </bean> <!--dao--> <bean id="bookDao" class="cn.books.dao.impl.BookDaoImpl"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!--biz--> <bean id="bookBiz" class="cn.books.biz.impl.BookBizImpl"> <property name="dao" ref="bookDao"></property> </bean> <!--事务管理器--> <bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven> </beans>
支持我们项目的一系列的jar包节点
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.3</version> </dependency> <!--jta的jar包--> <dependency> <groupId>javax.transaction</groupId> <artifactId>jta</artifactId> <version>1.1</version> </dependency> <!--mysql数据库驱动--> <dependency> <groupId>org.wisdom-framework</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.34_1</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.0.6.Final</version> </dependency> <!--以上是HIbernate的jar包配置--> <!--下面是Spring相关的jar包配置--> <!--c3p0--> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> <!--AOP的相关jar--> <dependency> <groupId> org.aspectj</groupId > <artifactId> aspectjweaver</artifactId > <version> 1.8.7</version > </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.2.0.RELEASE</version> </dependency> <!--Spring-ORM--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version> 4.2.2.RELEASE</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> </resources> </build>
前期准备工作完成,最后进入测试阶段:
package cn.books.test; import cn.books.beans.Book; import cn.books.biz.BookBiz; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Created by accp on 2017/3/29. */ public class FirstTest { @Test public void findTwo(){ ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContextbase.xml"); BookBiz proxy=(BookBiz) ctx.getBean("bookBiz"); int count = proxy.add(new Book("天空之城", "65")); System.out.println(count); } }
结果:
DEBUG SQL:92 - insert into Book (name, price) values (?, ?) Hibernate: insert into Book (name, price) values (?, ?)
DEBUG EntityPrinter:109 - cn.books.beans.Book{id=7, price=65, name=天空之城}
7
数据库数据:
使用查询功能:
添加方法:List<Book> selectAll();--------------->dao
private SessionFactory sessionFacctory;
@Transcational
public List<Book> selectAll() {
List<Book> list=sessionFactory.getCurrentSession().createCriteria(Book.class).list();
return list;
}
-------------------->dao.impl
List<Book> selectAll();--------------->biz
private BookDao dao;
public List<Book> selectAll(){
return dao.selectAll();
}
-------------------->biz.impl
applicationContext.xml配置文件不需要修改和添加,书写测试类即可。
@Test public void findOne(){ ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContextbase.xml"); BookBiz proxy=(BookBiz) ctx.getBean("bookBiz"); List<Book> list = proxy.selectAll(); for (Book item : list) { System.out.println("名称:"+item.getName()+" 价格:"+item.getPrice()); } }
控制台上的数据显示:
DEBUG SQL:92 - select this_.id as id1_0_0_, this_.name as name2_0_0_, this_.price as price3_0_0_ from Book this_ Hibernate: select this_.id as id1_0_0_, this_.name as name2_0_0_, this_.price as price3_0_0_ from Book this_
16:38:35,068 DEBUG EntityPrinter:102 - Listing entities: 16:38:35,068 DEBUG EntityPrinter:109 - cn.books.beans.Book{id=6, price=65, name=天空} 16:38:35,069 DEBUG EntityPrinter:109 - cn.books.beans.Book{id=5, price=65, name=天空} 16:38:35,069 DEBUG EntityPrinter:109 - cn.books.beans.Book{id=4, price=65, name=天空} 16:38:35,069 DEBUG EntityPrinter:109 - cn.books.beans.Book{id=3, price=65, name=你好吗?天空} 16:38:35,069 DEBUG EntityPrinter:109 - cn.books.beans.Book{id=2, price=45, name=图书第二次} 16:38:35,069 DEBUG EntityPrinter:109 - cn.books.beans.Book{id=1, price=45, name=图书} 16:38:35,069 DEBUG EntityPrinter:109 - cn.books.beans.Book{id=7, price=65, name=天空之城} 16:38:35,072 DEBUG HibernateTransactionManager:680 - Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey[cn.books.beans.Book#6], EntityKey[cn.books.beans.Book#5], EntityKey[cn.books.beans.Book#4], EntityKey[cn.books.beans.Book#3], EntityKey[cn.books.beans.Book#2], EntityKey[cn.books.beans.Book#1], EntityKey[cn.books.beans.Book#7]],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] after transaction
名称:图书 价格:45 名称:图书第二次 价格:45 名称:你好吗?天空 价格:65 名称:天空 价格:65 名称:天空 价格:65 名称:天空 价格:65 名称:天空之城 价格:65
在整合Spring和Hibernate时候遇到的问题最多的就是:
Could not obtain transaction-synchronized Session for current thread
提示无法获取当前线程的事务同步session,略微奇怪,这和事务有什么关系..然后百度一下有人说改成用openSession方法就好了,那我又百度了一下这2个方法的区别:
(1)openSession每次打开都是新的Session,所以多次获取的Session实例是不同的,并且需要人为的调用close方法进行Session关闭。
(2)getCurrentSession是从当前上下文中获取Session并且会绑定到当前线程,第一次调用时会创建一个Session实例,如果该Session未关闭,后续多次获取的是同一个Session实例;事务提交或者回滚时会自动关闭Sesison,无需人工关闭。
现在我们所做的测试都是在控制台上打印输出的,还没涉及到在页面上显示数据,当我们在页面上获得数据时要在保证在同一个会话中完成,所以当我们使用openSession()方法时不会出现错误,但是当我们在当前线程内获取session时会出现上述的错误。。
解决办法:
在dao层的方法上面加上@Transcational注解,在applicationContext.xml中添加上:
<!--事务管理器--> <bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>
或者换一种别的配置方法:
Aop方法
<!--事务管理器--> <bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean>
<tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="select*" isolation="DEFAULT" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="point" expression="execution(* *..biz.*.*(..))"></aop:pointcut> <aop:advisor advice-ref="txAdvice" pointcut-ref="point"></aop:advisor> </aop:config>
以上两种办法都可以解决上述的问题。。。。