一. Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式,如下图所示。
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory
,它是工厂模式的实现。BeanFactory
使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
二. IOC
1. 控制反转
控制反转(inverse of control)也称为DI(Didependency injection)的基本概念是:不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务,容器负责将这些联系在一起。初始化控制反转到容器中了,不在控制在自己手中定义的了;原来控制的是具体的实现,现在依赖的是抽象,控制的是接口,也可称为控制反转。
2. 注入方式:
(1)Set注入
这是最简单的注入方式,假设有一个SpringAction,类中需要实例化一个SpringDao对象,那么就可以定义一个private的SpringDao成员变量,然后创建SpringDao的set方法(这是ioc的注入入口):
public class SpringAction { //注入对象springDao private SpringDao springDao; //一定要写被注入对象的set方法 public void setSpringDao(SpringDao springDao) { this.springDao = springDao; } public void method(){ springDao.method(); } }
spring将SpringDaoImpl对象实例化并且调用SpringAction的setSpringDao方法将SpringDao注入:
<!--配置bean,配置后该类由spring管理--> <bean name="springAction" class="com.spring.action.SpringAction"> <!--依赖注入,配置当前类中相应的属性--> <property name="springDao" ref="springDao"></property> </bean> <!--配置SpringDaoImpl对象--> <bean name="springDao" class="com.spring.dao.impl.SpringDaoImpl"></bean>
(2)构造器注入
这种方式的注入是指带有参数的构造函数注入,如下:创建了两个成员变量SpringDao和User,但是并未设置对象的set方法,所以就不能支持第一种注入方式,这里的注入方式是在SpringAction的构造函数中注入,也就是说在创建SpringAction对象时要将SpringDao和User两个参数值传进来:
public class SpringAction { //注入对象springDao private SpringDao springDao; private User user; public SpringAction(SpringDao springDao,User user){ this.springDao = springDao; this.user = user; System.out.println("构造方法调用springDao和user"); } public void save(){ user.setName("aa"); springDao.save(user); } }
在XML文件中使用<constructor-arg>标签,
<!--配置bean,配置后该类由spring管理--> <bean name="springAction" class="com.spring.action.SpringAction"> <!--创建构造器注入,如果主类有带参的构造方法则需添加此配置--> <constructor-arg ref="springDao"></constructor-arg> <constructor-arg ref="user"></constructor-arg> </bean> <bean name="springDao" class="com.spring.dao.impl.SpringDaoImpl"></bean> <bean name="user" class="com.spring.entity.User"></bean>
解决构造方法参数的不确定性,你可能会遇到构造方法传入的两参数都是同类型的,为了分清哪个该赋对应值,则需要进行一些小处理:
下面是设置index,就是参数位置:
<bean name="springAction" class="com.bless.springdemo.action.SpringAction"> <constructor-arg index="0" ref="springDao"></constructor-arg> <constructor-arg index="1" ref="user"></constructor-arg> </bean>
另一种是设置参数类型:
<constructor-arg type="java.lang.String" ref=""/>
(3) Annotation 注入
① 第一步修改xml文件;
<beans xmlns="http://www.springframework.org/schema/beans"//beans里没有前缀的都是由它指定 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" //beans里xsi开头的找这个文件 xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd //对应上面的beans http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config/> //隐式加载了四个bean,用于处理annotation的注解
②添加提示功能,.xsd文件;preference/XML/XML Catalog里添加.xsd文件
Xsd文件定义的xml文件的语法,一个xml文件可由多个xsd确定
③使用
@Autowired
a) 默认按类型by type
b) 如果想用byName,使用@Qulifier
c) 写在private field(第三种注入形式)(不建议,破坏封装)
d) 如果写在set上,@qualifier需要写在参数上
@Autowired 默认按bytype自动寻找对应的类型
public void setUserDAO(@Qualifier("u") UserDAO userDAO){//寻找名字为u
this.userDAO = userDAO;
}
@Resource(重要)
e) 加入:j2ee/common-annotations.jar
f) 默认按名称,名称找不到,按类型
g) 可以指定特定名称
h) 推荐使用
i) 不足:如果没有源码,就无法运用annotation,只能使用xml
@Component @Service @Controller @Repository与component一样
初始化spring配置文件的时候,会自动扫描com.spring下的所有包,若发现有@component,则将该类初始化为一个对象,对象的key为@component("name")中指明的name,若不指明,则默认为类的名字首字母小写;
如果发现@Resource(name=”u”);则查看容器是否有名字叫u的bean,若有则将u注入到方法参数中,而后参数就会传人方法内,当然也就注入了成员变量里:
j) 初始化的名字默认为类名首字母小写
k) 可以指定初始化bean的名字
Xml:里加<context:component-scanbase-package="com.spring"/>//加了该句spring会自动扫描该包的component注解,进行相应的处理
@Component("u")
public class UserDAOImpl implementsUserDAO {
@Resource(name="u")
public void setUserDAO( UserDAO userDAO) {
this.userDAO= userDAO;
}
@Component("userService")//在容器里可以作为bean存在
public class UserService {}
UserService service = (UserService)ctx.getBean("userService");
@Scope
@PostConstruct =init-method; @PreDestroy = destroy-method;
三. AOP
面向切面编程(也叫面向方面),可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。
1. 面向切面编程Aspect-Oriented-Programming
a) 是对面向对象的思维方式的有力补充
b) 用途:权限,日志,效率检查,事务,异常管理,filter就是aop
2. 好处:可以动态的添加和删除在切面上的逻辑而不影响原来的执行代码
a) Filter
b) Struts2的interceptor
3. 概念:查文档即可
a) JoinPoint 连接点:加入切面的那个点,比如在某个方法之前加入切面,该方法就是连接点
b) PointCut JoinPoint的集合,@Pointcut("execution(public* com.bjsxt.service..*.add(..))")
c) Aspect(切面) 下面的LogInterceptor就是个切面
d) Advice 切面的逻辑,@ Before就是个逻辑在..之前,区别jointpoint
e) Target 被代理对象,逻辑要织入的对象
f) Weave
4. 问题:想要在源daoimpl代码基础上加日志或者一些功能,
(1) 继承daoimpl,extends daoimpl重写方法。
Daoimpl2 extends daoimpl{
@override
save(){ ….加代码 super.save();}
}
(2) 组合
daoimpl3 implement dao{
private userdao=new userdaoimpl();
save(){ ….加代码 dao.save();}
}
慎用继承,组合较好
5. Spring aop使用:注解 自己写时会用到注解
(1) xml中加:
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:aspectj-autoproxy/>//使用aspectj语法,spring采用了这个框架
(2) 代码
@Aspect //指定是个切面类 @Component public class LogInterceptor { @Before ("execution(public * com.bjsxt.service..*.add(..))")//excut..代表方法的执行,在这个方法执行之前执行下面的方法,第一个*代表返回值,..代表层次, publicvoid before() { System.out.println("methodbefore"); } @Aspect @Component public class LogInterceptor { @Pointcut("execution(public* com.bjsxt.dao..*.*(..))")//Execution方法运行,第一个*代表返回值,..代表所有子包,任何类的任何方法, public void myMethod(){}; // myMethod为pointcut的名字 @Before("myMethod()") //指上面定义的那个切入点集合 public void before() { System.out.println("methodbefore"); } @Around("myMethod()") public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable { System.out.println("methodaround start"); pjp.proceed(); System.out.println("methodaround end"); } }
@afterreturning @afterthrowing @around
cglib包若不是接口需用该包
Spring aop使用:xml
<bean id="logInterceptor"class="com.bjsxt.aop.LogInterceptor"></bean> <aop:config> <aop:aspectid="logAspect" ref="logInterceptor"> <aop:beforemethod="before" pointcut="execution(public *com.bjsxt.service..*.add(..))" /> </aop:aspect> </aop:config>
若没有切面类的逻辑,或使用第三方提供的逻辑类,就不能加注解了,所以xml必须会。
四. datasource
1. Spring 指定datasource
a) 参考文档,找dbcp.BasicDataSource 主要用到的三种连接池,要用注入的方式
i. c3p0
ii. dbcp
iii. proxool
b) 在DAO或者Service中注入dataSource
c) 在Spring中可以使用PropertyPlaceHolderConfigure来读取Properties文件的内容
(1)dbcp.BasicDataSource
datasource:提供了一个标准化的连接
<bean id="myDataSource"class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close"> <!-- results in asetDriverClassName(String) call --> <property name="driverClassName"value="com.mysql.jdbc.Driver"/> <property name="url"value="jdbc:mysql://localhost:3306/mydb"/> <property name="username"value="root"/> <property name="password"value="masterkaoli"/> </bean>
dao注入这个数据源。
private DataSource Datasource; public DataSource get Datasource() { returnDatasource; } @Resource publicvoid set Datasource(DataSourceDatasource) { this.Datasource = Datasource; }
还需要拿connction等,较古老。
(2)c3p0
配置参数影响因素:性能的要求要亲身测试(自动化测试工具,或写个多线程测试);硬件cpu等;内存的大小;网页执行时间影响;链接的长短;
(3)占位符配置,jdbc.propertites配置:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <propertyname="locations"> //此种情况都可以用propertites配置 <value>classpath:jdbc.properties</value> </property> </bean> <beanid="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <propertyname="driverClassName" value="${jdbc.driverClassName}"/> <propertyname="url" value="${jdbc.url}" /> <propertyname="username" value="${jdbc.username}" /> <propertyname="password" value="${jdbc.password}" /> </bean>
Jdbc.propertites文件:
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/spring jdbc.username=root jdbc.password=root
五. Spring整合Hibernate Spring_1700_Spring_DataSource参考
Opensession和getcurrentsession的区别?open是打开新的,需要自己写关闭,事务等
(1)知道即可
a) Spring中配置sessionfactory
<bean ..AnnotationSessionFactoryBean>
i. <property dataSource
ii. <annotatedClasses
b) 引入hibernate 系列jar包
c) User上加Annotation
d) UserDAO或者UserServie 注入SessionFactory
e) jar包问题一个一个解决
(2)声明式的事务管理
f) 事务加在DAO层还是Service层?
g) annotation Spring_1800_Spring_Hibernate_Transaction_Annotation
i. 加入annotation.xsd 即加三行tx代码
ii. 加入txManager bean
iii. <tx:annotation-driven
iv. 在需要事务的方法上加:@Transactional
v. 需要注意,使用SessionFactory.getCurrentSession 不要使用OpenSession
xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <beanid="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <propertyname="sessionFactory" ref="sessionFactory" /> </bean> <tx:annotation-driventransaction-manager="txManager"/>
注意:
Spring对事务管理简单很多了,dao不需要try catch了
h) @Transactional详解
i. 什么时候rollback
1. 运行期异常,非运行期异常不会触发rollback
2. 必须uncheck (没有catch)
3. 不管什么异常,只要你catch了,spring就会放弃管理
4. 事务传播特性:propagation_required
@Transactional(propagation=propagation.REQUIRED):如果有了transation,就用以前的,没有就创建一个。
5. read_only
@Transactional(readOnly=true) 用途,可以提高效率
i) xml(推荐,可以同时配置好多方法)
i. <bean txmanager
ii. <aop:config
1. <aop:pointcut
2. <aop:advisor pointcut-refadvice-ref
iii. <tx:advice: idtransaction-manager =
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <propertyname="sessionFactory" ref="sessionFactory" /> </bean> <aop:config> <aop:pointcut id="bussinessService" expression="execution(public* com.bjsxt.service..*.*(..))" /> <aop:advisorpointcut-ref="bussinessService" advice-ref="txAdvice"/> </aop:config> <tx:adviceid="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:methodname="getUser" read-only="true" />//get都是只读的 <tx:methodname="add*" propagation="REQUIRED"/>//读写都行 </tx:attributes> </tx:advice>
(3)自动扫描实体类
<!-- <propertyname="annotatedClasses"> <list> <value>com.bjsxt.model.User</value> <value>com.bjsxt.model.Log</value> </list> </property> --> <propertyname="packagesToScan"> //自动扫描实体类,自己就不用加了 <list> <value>com.bjsxt.model</value> </list> </property>
HibernateTemplate、HibernateCallback、HibernateDaoSupport(不重要)介绍
iv. 设计模式:Template Method (按照模板,具体内容自己往里填即可)
前面的打开session,关闭session,事务提交等都作为模板
v. Callback:回调/钩子函数
vi. 第一种:(建议)
1. 在spring中初始化HibernateTemplate,注入sessionFactory
2. DAO里注入HibernateTemplate
3. save写getHibernateTemplate.save();
<bean id="hibernateTemplate"class="org.springframework.orm.hibernate3.HibernateTemplate"> <propertyname="sessionFactory"ref="sessionFactory"></property> </bean> public class UserDAOImpl implementsUserDAO { privateHibernateTemplate hibernateTemplate; publicHibernateTemplate getHibernateTemplate() { returnhibernateTemplate; } @Resource publicvoid setHibernateTemplate(HibernateTemplate hibernateTemplate) { this.hibernateTemplate= hibernateTemplate; } publicvoid save(User user) { hibernateTemplate.save(user); //thrownew RuntimeException("exeption!"); } }
vii. 第二种:
1. 从HibernateDaoSupport继承(不需要)
2. 必须写在xml文件中,无法使用Annotation,因为set方法在父类中,而且是final的
也可以编写superdao简化代码,SuperDAO.java但以后就不能继承其他类了。
如Spring_2100_Spring_Hibernate_HibernateDaoSupport
或者Spring_2200_Spring_Hibernate_HibernateDaoSupport_2