- 浏览: 23107 次
- 性别:
- 来自: 广州
-
文章分类
最新评论
1 什么是spring ?
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架.
spring的设计思想是,单例模式和工厂模式
2 spring的四大特点(优点)
轻量级,低侵入的设计
Spring的DI机制降低了业务对象替换的复杂性
spring不依赖于web容器,独立于各种应用服务器, Write Once,Run Anywhere(一次编译到处运行)
高度开放性:Spring并不完全依赖于Spring,开发者可自由选用Spring框架的部分或全部,它的架构仍然是内在稳定的
3 spring的组成部分 七大模块
Spring Core:Spring的基石,提供了Spring的最主要的核心机制:控制反转和依赖注入
Spring Context:提供了Spring的上下文信息,如:国际化,验证等
Spring Web支持:简化了处理多部分请求
Spring MVC框架支持:一个全功能的构建 Web 应用程序的 MVC 实现,MVC 容纳了大量视图技术,其中包括 JSP、Velocity等。
Spring Dao支持:Spring的Dao支持大大的简化了JDBC操作数据库所带来的繁琐
Spring ORM支持 pring框架集成了若干ORM框架,从而提供了ORM的对象关系工具,其中包括 JDO、Hibernate、iBatis和TopLink。
所有这些都遵从Spring的通用事务和DAO异常层结构。
Spring AOP:面向方面编程,提供了事务,日志,权限,安全等处理机制
具体解释
Spring 核心容器(Core):提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,它
是工厂模式的实现。BeanFactory使用控制反转(Ioc)模式将应用程序的配置和依赖性规范与实际的应
用代码程序分开。
Spring AOP:通过配置管理特性,Spring AOP模块直接面向方面的编程功能集成到了Spring框架中,所以可以很容易的使Spring框架管理的任何对象支持 AOP。Spring AOP模块为基于Spring的应用程序
中的对象提供了事务管理服务。通过使用Spring AOP,不用依赖于EJB组件,就可以将声明性事务管理
集成到应用程序中。
Spring ORM:Spring框架集成了若干ORM框架,从而提供了ORM的对象关系工具,其中包括 JDO、Hibernate、iBatis和TopLink。所有这些都遵从Spring的通用事务和DAO异常层结构。
Spring DAO:JDBC DAO抽象层提供了有意义的异常层次的结构,可用该结构来管理异常处理和不同数据供应商抛出的异常错误信息。异常层次结构简化了错误处理,并且大大的降低 了需要编写的异常代码数量(例如,打开和关系连接)。Spring DAO的面向JDBC的异常遵从通用的DAO异常层结构。
Spring WEB:Web上下文模块建立在上下文模块(Context)的基础之上,为基于Web服务的应用
程序提供了上下文的服务。所以Spring框架支持 Jakarta Struts的集成。Web模块还简化了处理多部分请求
及将请求参数绑定到域对象的工作
Spring上下文(Context):Spring上下文是一个配置文件,向Spring框架提供上下文信息。
Spring上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化校验和调度功能。
Spring MVC:Spring的MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,
MVC框架变成为高度可配置的,MVC容纳的大量视图技术,包括JSP、Velocity、Tiles、iText和Pol
4 spring的核心机制
1).控制反转(IoC/Inverse Of Control):调用者不再创建被调用者的实例,由spring框架实现(容器创建)所以称为控制反转。
2).依赖注入(DI/Dependence injection) :创建好实例后再注入调用者称为依赖注入。
当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,
在传统的程序设计过程中,通常由调用者来创建被调用者的实例, 但在Spring里,创建被调用者的工
作不再由调用者来完成,因此称为控制反转; 创建被调用者 实例的工作通常由Spring容器来完成,
然后注入调用者,因此也称为依赖注入
什么是ioc容器
bean工厂(BeanFactory) 和 应用上下文(Application Context)
在Spring中,BeanFactory是IoC容器的核心接口。 它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
BeanFactory
|
|
ApplicationContext(国际化)
/ \
/ \
FileSystemXmlApplicationContext ClassPathXmlApplicationContext
常用有三种方式可以得到BeanFactory ,从而bean实例,并进行调用
// InputStream is = new FileInputStream("beans.xml");
// InputStreamResource isr = new InputStreamResource(is);
// BeanFactory beanFactory = new XmlBeanFactory(isr);
//
// Spring给出一些BeanFactory的实现类,其中最为常用的是XmlBeanFactory。
// 1、通过文件系统
// Resource res = new FileSystemResource("src/beans.xml");
// XmlBeanFactory beanFactory = new XmlBeanFactory(res);
// 2、通过类路径(class路径 ./表示上级目录)
// ClassPathResource res = new ClassPathResource("./beans.xml");
// XmlBeanFactory beanFactory = new XmlBeanFactory(res);
// 3、通过ApplicationContext加载(ClassPathXmlApplicationContext或者FileSystemXmlApplicationContext)
// ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
// new String[] {"./beans.xml"});
// BeanFactory beanFactory = (BeanFactory) appContext;
//
// ClassPathResource res = new ClassPathResource("./beans.xml");
// XmlBeanFactory beanFactory = new XmlBeanFactory(res);
或者 ApplicationContext ctx=new FileSystemXmlApplicationContext("src/bean.xml");
ApplicationContext增加功能 1国际化2事件支持
国际化测试
(1)bean配置
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>message</value>
<!-- 如果有多个资源文件,全部列在此处-->
</list>
</property>
</bean>
(2)
ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
String[] a = {"读者"};
String hello = ctx.getMessage("hello",a,Locale.ENGLISH);//英文
Object[] b = {new Date()};
String now = ctx.getMessage("hello",b,Locale.getDefault());//默认
System.out.println(hello);
System.out.println(now);
5 简单测试BeanFactory
<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="aaa" class="包名.类名"/>
</beans>
测试 FileSystemXmlApplicationContext默认从项目目录寻找bean配置文件xml
ApplicationContext ctx = new FileSystemXmlApplicationContext("src/bean.xml");
Test t=(Test)ctx.getBean("aaa");
System.out.println(t.getName());
依赖注入的优点,代码将更加清晰,Spring管理bean的灵巧性, bean与bean之间的依赖关系放在配置文件里组织,
不再担心对象之间的依赖关系之后,实现更高层次的松耦合将易如反掌
依赖注入的方式 (为什么叫依赖注入 类的四种关系 )
(1)set注入(2)构造注入(3)lookup方法注入
setter注入实例
<bean id="aaa" class="包名.类名">
<property name="属性名">
<ref local="另一个bean id"/>//local与bean的区别
</property>
</bean>
//local与bean的区别 local:当前xml bean:整个spring容器
构造注入实例 提供构造方法(注入的实例参数) 要提供无参的构造方法
<bean id="aaa" class="包名.类名">
<constructor-arg><ref bean="steelAxe"/></constructor-arg>
</bean>
(3)lookup方法注入(依赖注入的bean每次都创建一个新实例)
这种方法主要是用在Singleton的Object中使用非Singleton的Bean时,
通过lookup-method的那个方法来取得非Singleton的Bean。一般用的不多,在用这种定义之前最佳想明白你的需求。
1 Singleton的Object 中提供一个抽象方法,返回非Singleton的Bean,此时Singleton的类变成抽象类 如
public abstract class Test//Singleton的Bean {
TestBean tb;//非Singleton的Bean时
public TestBean getTb() {
return tb;
}
public void setTb(TestBean tb) {
this.tb = tb;
}
public abstract TestBean createXxx();
}
2 配置xml
<bean id="testbean" class="com.TestBean" singleton="false"/>//注意singleton="false"
<bean id="test" class="com.Test">
<property name="tb"> <ref local="testbean"/></property>//注意这个依然不能少
<lookup-method name="createXxx" bean="testbean"/>
</bean>
3 测试
Test t=(Test)ctx.getBean("test");
System.out.println("不使用lookup-method注入");
TestBean tb1=t.getTb();
TestBean tb2=t.getTb();
System.out.println(tb1==tb2);
System.out.println("使用lookup-method注入");
TestBean tb3=t.createXxx();
TestBean tb4=t.createXxx();
System.out.println(tb3==tb4);
结果
不使用lookup-method注入
true
使用lookup-method注入
false
注入其他属性例子
<beans>
<bean id="aaa" class="包名.类名"/>
<bean id="bbb" class="lee.Chinese">
<property name="schools">
<list>
<value>小学</value>
<value>中学</value>
<value>大学</value>
</list>
</property>
<property name="score">
<map>
<entry key="数学">
<value>87</value>
</entry>
<entry key="英语">
<value>89</value>
</entry>
<entry key="语文">
<value>82</value>
</entry>
</map>
</property>
<property name="health">
<props>
<prop key="血压">正常</prop>
<prop key="身高">175</prop>
</props>
</property>
<property name="axes">
<set>
<value>xxx</value>
<bean class="包名.类名"/>
<ref local="另外一个bean id"/>
</set>
</property>
</bean>
</beans>
上述中的health指的是Properties属性类
private Properties health = new Properties();
测试 Spring的DI机制降低了业务对象替换的复杂性 面向接口编程的好处 灵活配置
6 spring bean的实例 创建的几种方式
(1)构造器 单例思想
(2)静态工厂(静态方法创建)
静态方法名(iint type)
<bean id="xxx" class="包名.类名(工厂类)" factory-method="静态方法名">
<constructor-arg value="1"></constructor-arg>
</bean>
创建同一接口下不同实例
(3)工厂方法(非静态方法创建)
<bean id="aaa" class="com.PersonFactory(工厂类)">
<property name="type"><value>1</value></property>
</bean>
<bean id="xxx" factory-bean="工厂bean id" factory-method="非静态方法名">
7 自动装配
有两个bean A与B
B作为A的一个属性,当我们没有通过setter注入或者构造注入B实例时,我们可以在A bean中指定autowire属性,
让它在spring容器个根据不同方式自动寻找b实例
自动装配的优缺点:
优点:自动装配能显著减少配置的数量,自动装配可以使配置与java代码同步更新
缺点:Spring会尽量避免在装配不明确的时候进行猜测,容器中可能存在多个bean定义跟自动装配的
setter方法和构造器参数类型匹配
byName(用于set注入) 根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。例如,在bean定义中将autowire设置为by name,而该bean包含master属性(同时提供setMaster(..)方法),Spring就会查找名为master的bean定义,并用它来装配给master属性。
byType 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配。若没有找到相匹配的bean,则什么事都不发生,属性也不会被设置。如果你不希望这样,那么可以通过设置dependency-check="objects"让Spring抛出异常。
constructor 与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
autodetect 通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。
在用byType时候,如果没有匹配的bean 可测试dependency-check="objects"让Spring抛出异常
8 spring框架中bean的生命周期?
(1) bean定义
在配置文件里面用<bean></bean>来进行定义。
(2) bean初始化
有两种方式初始化: 也可同时使用。参数指定的后执行
A.在配置文件中通过指定init-method属性来完成
B.实现org.springframwork.beans.factory.InitializingBean接口 实现afterPropertiesSet()方法
(3) bean调用
有三种方式可以得到bean实例,并进行调用
(4) bean销毁
销毁有两种方式。也可同时使用参数指定的销毁方法后运行
A.使用配置文件指定的destroy-method属性
B.实现org.springframwork.bean.factory.DisposableBean接口 实现destroy()方法
可以通过调用ConfigurableListableBeanFactory(XmlBeanFactory)里的destroySingletons销毁单例对象,测试destroy()方
ConfigurableListableBeanFactory beanFactory =
new XmlBeanFactory(new FileSystemResource("src/bean.xml"));
beanFactory.destroySingletons();
}
是的, 当调用beanFactory.destroySingletons()方法的时候,bean不会马上销毁,但是容器在销毁bean之前,会等到方法结束剩余的任务后
再调用相应的销毁bean之前指定的其他方法。再干掉bean
在 spring 2.5中 ((AbstractApplicationContext)beanFactory).registerShutdownHook();来看看bean的销毁
原型 bean 在创建后即脱离 BeanFactory 的维护,所以只能调用初始化方法,而不能做清理工作。
如果不是Singleton的Bean不能触发结束初始化事件和预销毁事件么?那是因为如果不是单例模式的Bean,Spring不会自己去管理,而是把它们交给Spring框架下的应用本身去管理,这样就相当于把Bean交给了GC。但是如果是单例模式的Bean,Spring会建立一个Bean的列表来统一管理,在Spring应用被关闭的时候,会执行BeanFactory中的destroySingltons()方法来逐个销毁列表中的Bean。这就是为什么只有单例模式实现Spring的那两个事件接口或指定方法属性才是有效的
可以考虑引入bean的后处理技术
9 spring 中bean的作用域(5种):2.0以前只有单例和非单例 2。0以后有以下5种
singleton
在每个Spring IoC容器中一个bean定义对应一个对象实例。
prototype
一个bean定义对应多个对象实例。
request
在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例, 它们依
据某个bean定义创建而成。该作用 域仅在基于web的Spring ApplicationContext情形下有效。
session
在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring
ApplicationContext情形下有效。
global session
在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet
context的时候有效。该作用域仅在基于 web的Spring ApplicationContext情形下有效。
10 spring在web环境中的配置(2种)
1.在Web.xml中配置上下文载入器
根据你的系统情况,你可以选择两种上下文载入器:ContextLoaderListener和ContextLoaderServlet.
如果你的Web容器支持Servlet2.3标准或更高,你可以使用两者,否则只能使用后者.
(1)ContextLoaderListener在Web.xml应该如下配置:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
(2)ContextLoaderServlet在Web.xml应该如下配置:
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>
org.springframework.web.context.ContextLoaderServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
2.指定上下文载入器的配置文件
不论你使用的那种上下文载入器,你都应该指明Spring配置文件的位置.如果没有指定,上下文载入器将把/web-inf/applicationContext.xml当作Spring配置文件。
要指定Spring配置文件的位置,你可以在Servlet上下文设置contextConfigLocation参数来为上下文载入器指定一个或多个Spring配置文件
(使用通配符或是用逗号隔开)。如下所示:
<context-param>
<param-name>
contextConfigLocation
</param-name>
<param-value>
/WEB-INF/bean.xml
</param-value>
</context-param>
3.获得应用上下文
接下来我们就可以获得ApplicationContext了,代码如下:
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
在一个自启动的Servlet中,我们可以这样获得它:
public class InitialSystemServlet extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
// 取得Spring的上下文
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());
}
测试web应用环境相关的Bean作用域
spring 2.5 dtd配置
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-2.5.xsd">
<bean id="test" class="com.Test" >
</bean>
</beans>
如果用户使用spring的webApplicationContext,则可以使用另外3种Bean的作用域:request,session和globalSession.不过
在使用这些作用域之前,首先必须在web容器中进行一些额外的配置,在高版本的web容器中,则可以利用HTTP请求监听器进行配置:
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
细心的同学可能有一个疑问:在介绍webApplicationContext初始化时,我们已经通过ContextLoaderListener将web容器与
spring容器整合,为什么这里又要引入一个额外的RequestContextListener以支持Bean的另外3个作用域呢?
在整合spring容器时使用ContextLoaderListener,它实现了ServletContextListener监听器接口,ServletContextListener
只负责监听web容器启动和关闭的事件.而RequestContextListener实现ServletRequestListener监听器接口,该监听器监听
HTTP请求事件,web服务器接收的每一次请求都会通知该监听器.
spring容器启动和关闭操作由web容器的启动和关闭事件触发,但如果spring容器中的Bean需要request,session,globalsession
作用域的支持,spring容器本身就必须获得web容器的HTTP请求事件,以HTTP请求的事件"驱动"Bean作用域的控制逻辑.
11 spring 对dao的支持
<1>dao模式优点
减少开发代码量 提高工作效率
降低系统资源消耗 提高系统性能
业务逻辑层与持久层(数据层)的分离,使数据与操作更为清晰。
数据访问独立到了一层,修改具体实现类,不影响系统的架构运行
<2>DAO模式的四个组件
DAO接口
DAO接口实现类
pojo值对象
DAO实例的定位(工厂 或 spring注入)
2. 核心类
JdbcTemplate(需要注入DataSource)
JdbcDaoSupport类(简化注入,有一个字段dataSource)
并提供了getJdbcTemplate()方法获得JdbcTemplate实例
DataSource接口
为了从数据库中取得数据,我们首先需要获取一个数据库连接。Spring通过DataSource对象来完成这个工作。
DataSource是JDBC规范的一部分,它被视为一个通用的数据库连接工厂。通过使用DataSource,
Container或Framework可以将连接池以及事务管理的细节从应用代码中分离出来。
作为一个开发人员,在开发和测试产品的过程中,你可能需要知道连接数据库的细节。
但在产品实施时,你不需要知道这些细节。通常数据库管理员会帮你设置好数据源。
在使用Spring JDBC时,你既可以通过JNDI获得数据源,也可以自行配置数据源(使用Spring提供的DataSource实现类)。
使用后者可以更方便的脱离Web容器来进行单元测试。 这里我们将使用DriverManagerDataSource
,不过DataSource有多种实现, 后面我们会讲到。使用DriverManagerDataSource和你以前获取一个JDBC连接 的做法没什么两样。
你首先必须指定JDBC驱动程序的全限定名,这样DriverManager 才能加载JDBC驱动类,接着你必须提供一个url(因JDBC驱动而异,
为了保证设置正确请参考相关JDBC驱动的文档), 最后你必须提供一个用户连接数据库的用户名和密码。
目前已经有开源的免费用了
DataSource
/ \
/ \
DriverManagerDataSource org.apache.commons.dbcp.BasicDataSource
下面我们将通过一个例子来说明如何配置一个 DataSource ,
1 自己实现DataSource接口,设置数据库相关连接信息
2 使用现有的实现类dataSource 编程方式 获得dataSourc 如下
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver<");
dataSource.setUrl("jdbc:mysql://localhost:3306/j2ee");
dataSource.setUsername("root");
dataSource.setPassword("123456");
3 通过开源dbcp获得dataSource ,spring方式
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/j2ee</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>123456</value>
</property>
</bean>
使用Spring的Dao支持来写Dao层,继承JdbcDaoSupport类,JdbcDaoSupport类中有一个字段dataSource
也就是数据库连接,因此只需继承JdbcDaoSupport类,并给它注入dataSource,就隐式的获得了数据库连接,可以在bean.xml文件中
注入connection(即:dataSource)
<beans>
<!-- spring 方式获得dataSource-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/j2ee</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>123456</value>
</property>
</bean>
<bean id="xxx" class="包名.类名(dao的实现类)">
<property name="dataSource">
<ref local="dataSource"/>
</property>
</bean>
</beans>
3.在这个Dao 实现类中写一个内部类,使其实现:RowMapper接口,用来封装成具体的pojo对象,代码如下
private class PersonRowMapper implements RowMapper
{
public Object mapRow(ResultSet resultSet, int rowNumber)
throws SQLException {
User user = new User();
user.setId(resultSet.getLong("id"));
user.setName(resultSet.getString("name"));
user.setSex(resultSet.getString("sex"));
user.setAge(resultSet.getInt("age"));
user.setAddr(resultSet.getString("addr"));
return user;
}
}
4 通过JdbcTemplate类进行增删查询修改操作
(1)增加 修改 删除示例
public void createPerson(PersonBean p)
{
Object[] args = {p.getName() , new Integer(p.getAge()) };
getJdbcTemplate().update("insert into person_test(p_name,p_age) values(?,?)", args );
}
(2)查询 返回单个object
public PersonBean getPerson(int id)
{
Object[] args = {new Integer(id)};
//PersonRowMapper是刚刚的内部类
return (PersonBean)getJdbcTemplate().queryForObject("select p_name,p_age from person_test where p_id = ?", args, new PersonRowMapper());
}
(3)返回list
public List findPersonsByName(String name)
{
//PersonRowMapper是刚刚的内部类
return getJdbcTemplate().query("select * from person_test where p_name like '%" + name +"%'" , new PersonRowMapper());
}
5 spring 2.5以后提供了一个SimpleJdbcTemplate类来操作
2.5例子
public class PersonDaoSpring25 implements PersonDao {
private SimpleJdbcTemplate simpleJdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
}
@Override
public void add(Person p) {
// TODO Auto-generated method stub
String sql = "insert into person(name) values(?)";
simpleJdbcTemplate.update(sql, p.getName());
}
@Override
public void del(String id) {
// TODO Auto-generated method stub
String sql="delete from person where id=?";
simpleJdbcTemplate.update(sql, id);
}
@Override
public List findAll() {
// TODO Auto-generated method stub
String sql = "select * from person";
List list = simpleJdbcTemplate.getJdbcOperations().query(sql,
new BeanPropertyRowMapper(Person.class));
return list;
}
@Override
public Person findById(String id) {
String sql = "select * from person where id=?";
Person p = simpleJdbcTemplate.queryForObject(sql,
ParameterizedBeanPropertyRowMapper.newInstance(Person.class),
id);
return p;
}
@Override
public void update(Person p) {
String sql = "update person set name=? where s_id=?";
simpleJdbcTemplate.update(sql, p.getName(), p.getId());
}
}
12 spring aop
AOP的好处:
消除了编码模块之间的依赖
可以在任意阶段,向已有功能模块中填加新功能,且不侵入原有功能
AOP的特征:
各步骤之间的良好隔离性 , 源代码的无关性
Spring 面向方面编程(AOP) spring支持AOP功能,AspectJ更完美的支持AOP
AOP 的核心构造是方面,它将那些影响多个类的行为封装到可重用的模块中, 将系统中通用的需求功能隔离出来形成一个功能模块,
并将这个模块切入到应用程序当中, AOP追求的是调用者与被调用者的解耦,从而消除了OOP引起的代码混乱和分散问题,
增强了系统的可维护性和代码的重用性
方面:哪方面 系统中分为业务方面的和非业务方面 Spring主要集中于非业务方面 如(日志、事务、安全、权限等)
1.面向方面与面向切面:AOP的实现中的几个重要的概念:
1.1如果理解为“面向方面编程”:
针对于某一模块进行专门的编写(如:面向日志编程,面向事务编程,面向权限等),其意思就是说面向具体的某个功能模块来编程,然后将其切入到项目中
1.2如果理解为“面向切面编程”:
连接点:程序执行过程中明确的点,如方法的调用或者异常的抛出,举个例子,如果是一个权限系统的话,要控制到类中的某一个具体的方法,那么这个方法就是一个连接点
切入点:连接点的集合,如类中多个个方法的调用, 还是以权限系统来举例,如果要控制一个类中的多个方法的话,那么这几个方法(也即是几个连接点)组成了一个切入点
切面:如果要控制多个类中的多个方法,那么这多个类就组成了一个切面
连接点 --- 切入点 ---- 切面(三者之间的关系可以形象的理解为:点--线--面)
2.1.连接点 --- 切入点 ---- 切面 --- 方面(解决方案的切入点)
2.2.目标对象(也就是:寻找被处理的类)
2.3.AOP代理(具体实现),分为二种,
JDK动态代理(面向接口)
Cglib代理(面向具体类)
2.4.处理(Spring AOP处理)或者叫通知,aop框架在特定的连接点执行的动作,Spring提供了五种处理方式
2.5 Advisor=(处理+切入点)
2.6 下面介绍Spring的处理
实现步骤
(1)目标对象定义 bean定义
(2) 处理与Advisor
<1> 处理 定义(1 在哪里处理<连接点 --- 切入点 ---- 切面 --- 方面> 2什么方式处理<如前处理,后处理,前后都处理>)
如果只是简单的定义处理,则默认的切入点是目标类的所有方法都处理
<2> 如果希望更精确的切入点,则可以采用Advisor(切入点+处理),以下是采用正则表达式支持类RegexpMethodPointcutAdvisor的示例
配置Advisor (Advisor=切入点+通知)
<bean id="testAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!-- advice属性确定处理bean-->
<property name="advice">
<!-- 此处的处理bean定义采用嵌套bean,也可引用容器的另一个bean-->
<bean class="包名.通知bean类名" />
</property>
<!-- patterns确定正则表达式模式-->
<property name="patterns">
<list>
<!-- 确定正则表达式列表-->
<value>.*say.*</value> <!-- 业务实现方法名匹配 -->
</list>
</property>
</bean>
(3) aop代理对象定义 bean 定义
<0>手写aop代理(编程式)
<1>采用ProxyFactoryBean生成代理
特点:一种接口或者一个类 都需要对应的一个具体代理,需要指定接口或者类 以及对应的代理定义
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--当用面向具体类实现时 proxyInterfaces属性可以不用注入 此时采用Cglib代理,必须加入Cglib的jar包 -->
<property name="proxyInterfaces">
<value>包名.目标对象的接口</value>
</property>
<property name="target">
<ref local="目标对象的bean id"/>
</property>
<property name="interceptorNames">
<list>
<value>处理bean id</value><!-- list说明可以注入多个处理 -->
</list>
</property>
</bean>
<2> 自动代理 主要采用了 bean的后处理技术 实现了bean的后处理接口BeanPostProcessor,通常有两个常用的实现类
在spring bean 的生命周期中,可以在bean创建之后(如指定init-method),销毁之前(指定distory-method),让容器
执行特定的方法,如果有更多的方法,需要在创建之时(注意是创建之时)被调用,可采用实现BeanPostProcessor接口
使用BeanPostProcessor,让我们的bean实现BeanPostProcessor接口
1 public class Chinese implements Person,BeanPostProcessor{
@Override
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("你好");
}
@Override
public Object postProcessAfterInitialization(Object arg0, String arg1)
throws BeansException {
// TODO Auto-generated method stub
System.out.println("进入postProcessAfterInitialization方法");
System.out.println(arg1);//返回之前可以包装一下
return arg0;
}
@Override
public Object postProcessBeforeInitialization(Object arg0, String arg1)
throws BeansException {
// TODO Auto-generated method stub
System.out.println("进入postProcessBeforeInitialization方法");
System.out.println(arg1);//返回之前可以包装一下
return arg0;
}
}
2 客户端调用
Resource res = new FileSystemResource("src/beans.xml");
XmlBeanFactory beanFactory = new XmlBeanFactory(res);
Chinese c = new Chinese();
beanFactory.addBeanPostProcessor(c);//注意这句哦,注册BeanPostProcessor
Person p = (Person)beanFactory.getBean("chinese");
spring为我们提供了以下两种实现
BeanPostProcessor
/ \
/ \
BeanNameAutoProxyCreator DefaultAdvisorAutoProxyCreator
<2.1> 采用BeanNameAutoProxyCreator自动生成代理
特点:多种接口或者多个类 自动创建其对应代理,需要指定接口或者类。接口或者类共用一个自动代理
<!-- 定义BeanNameAutoProxyCreator-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!-- 指定对满足哪些bean name的bean自动生成业务代理 -->
<property name="beanNames">
<!-- 下面是所有需要自动创建代理的bean-->
<list>
<value>bean id 1</value>
<value>bean id 2</value>
</list>
</property>
<!-- 下面定义BeanNameAutoProxyCreator所需的处理-->
<property name="interceptorNames">
<list>
<value>处理 bean 1</value>
<value>处理 bean 2</value>
</list>
</property>
</bean>
<2.2> 更牛的自动代理DefaultAdvisorAutoProxyCreator,
特点:多种接口或者多个类 自动创建其对应代理,不需要指定接口或者类,提供Advisor(切入点+通知),默认搜索所有的Advisor 如前面的正则表达式
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
(1).before advice(前置通知) implements MethodBeforeAdvice 重写before()方法
是在目标bean方法调用前调用,没有返回值,通常意外情况下,会继续运行下一步方法.记住的一点是没有返回
例子如下
public class MyBeforeAdvisor implements MethodBeforeAdvice
{
public void before(Method m, Object[] args, Object target) throws Throwable
{
System.out.println("方法调用之前...");
System.out.println("下面是方法调用的信息:");
System.out.println("所执行的方法是:" + m);
System.out.println("调用方法的参数是:" + args);
System.out.println("目标对象是:" + target);
System.out.println("方法调用之前111...");
}
}
(2).after advice(后置通知) implements AfterReturningAdvice 重写afterReturning()方法
是在方法调用后调用,有返回值,记住的一点是有返回值。
public void afterReturning(Object returnValue, Method m, Object[] args, Object target)throws Throwable
{
System.out.println("方法调用结束...");
System.out.println("目标方法的返回值是 : " + returnValue);
System.out.println("目标方法是 : " + m);
System.out.println("目标方法的参数是 : " + args);
System.out.println("目标对象是 : " + target);
}
(3).around advice(环绕通知) implements MethodInterceptor 重写其内的invoke()方法,实现方式与Struts2的拦截器一模一样
调用其 MethodInvocation 的proceed()方法;
例子如下
public class MyAroundInterceptor implements MethodInterceptor
{
public Object invoke(MethodInvocation invocation) throws Throwable
{
System.out.println("调用生小孩方法之前娶老婆: invocation对象:[" + invocation + "]");
Object rval = invocation.proceed();
System.out.println("调用方法之后...坐月子");
return rval;
}
}
(4).throws advice(异常通知) implements ThrowsAdvice
例子如下
public class MyExceptionAdvice implements ThrowsAdvice
{
public void afterThrowing(ClassNotFoundException ex) throws Throwable
{
System.out.println("系统抛出ClassNotFoundException异常,异常提示为: " + ex.getMessage());
}
public void afterThrowing(Method m,Object[] o,Object target,Throwable e)throws Throwable{
System.out.println("消息:"+e.getMessage());
}
public void afterThrowing(Method m, Object[] args, Object target, ArithmeticException ex)
{
System.out.println("系统抛出ArithmeticException异常,异常提示为: " + ex.getMessage());
System.out.println("抛出异常的方法为: " + m);
System.out.println("抛出异常的方法的参数为: " + args);
System.out.println("抛出异常的目标对象为: " + target);
}
}
(5).introduce advice(引入通知)
引入通知是一种特殊的通知,它能将新的成员变量、成员方法引入到目标类中。它不能作用于任何切入点,
因为它只作用于类层次,而不是方法层次。实现引入通知需要实现IntroductionAdvisor和IntroductionInterceptor接口。
引入通知不能调用proceed方法。Advisor必须针对每个实例,并且是有状态的。
引入通知的效果类似于设计模式中的访问者模式(Visitor Pattern)
3.AOP实现过程中的几种不同的方式:
3.1:拦截一类中所有的方法(连接点)
3.2:拦截一个类中的某些符合条件的方法(切入点)
3.3:拦截多个类中的符合条件的方法(切面)
4 利用aop进行事务编程 Spring事务配置的五种方式 (掌握Spring事务体系图)
传统上,J2EE开发者有两个事务管理的选择: 全局 或 本地事务(局部事务)。全局事务由应用服务器管理,使用JTA。
局部事务是和资源相关的,比如一个和JDBC连接关联的事务
事务种类分为: jdbc事务(局部事务) jta事务(全局事务) 容器事务
1、JDBC事务控制的局限性在一个数据库连接内,但是其使用简单。局部事务
2、JTA事务的功能强大,事务可以跨越多个数据库或多个DAO,使用也比较复杂。全局事务
3、容器事务,主要指的是J2EE应用服务器提供的事务管理,局限于EJB应用
两种事务的比较
1、JDBC事务控制的局限性在一个数据库连接内,但是其使用简单。
2、JTA事务的功能强大,事务可以跨越多个数据库或多个DAO,使用也比较复杂
从实现的角度划分
Spring把事务分为两种一种是:编程式事务,一种是声明式事务。
编程式事务是侵入式事务 比较灵活,编程式事务则要操作逻辑代码。存在重复的代码比较多,相对繁琐,而且不利于系统的扩展;
声明式事务是非侵入式的事务。声明式事务只需在配置文件中配置,而不需要去操作逻辑代码。
spring事务的7大传播属性
1.PROPAGATION_MANDATORY:要求调用该方法的线程必须处于事务环境中,否则抛出异常。
2.PROPAGATION_NESTED:如果执行该方法的线程已处于事务环境下,依然启动新的事务,方法在嵌套的事务里执行。
如果执行该方法的线程并未处于事务中,也启动新的事务,然后执行该方法,此时与PROPAGATION_REQUIRED相同。
3.PROPAGATION_NEVER:不允许调用该方法的线程处于事务环境下,如果调用该方法的线程处于事务环境下,则抛出异常。
4.PEOPAGATION_NOT_SUPPORTED:如果调用该方法的线程处于在事务中,则先暂停当前事务,然后执行该方法。
5.PEOPAGATION_REQUIRED:要求在事务环境中执行该方法,如果当前执行线程已处于事务中,则直接调用,
如果当前执行线程不已处于事务中,则启动新的事务后执行该方法。
6.PEOPAGATION_REQUIRES_NEW:该方法要求有一个在新的事务环境中执行,如果当前执行线程已处于事务中,
先暂停当前事务,启动新的事务后执行该方法;如果当前执行线程不已处于事务中,则启动新的事务后执行该方法。
7.PEOPAGATION_SUPPORTS:如果当前执行线程已处于事务中,则使用当前事务,否则不使用事务。
Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部 DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。根据代理机制的不同,总结了五种Spring事务的配置方式
现在以dataSource为例,当然要先配置dataSource,参见去前面文档spring方式获得dataSource部分
<1> 每个bean有一个代理
<1.1>配置事务管理器transactionManager
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 给DataSourceTransactionManager注入dataSource-->
<property name="dataSource"><ref local="dataSource"/></property>
</bean>
<1.2>配置事务代理bean TransactionProxyFactoryBean
<bean id="xxx"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 配置事务管理器 引用上面配置的来注入 -->
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="操作数据库的目标 dao bean id" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<2> 所有Bean共享一个代理基类 实则上就是spring 的模板机制 配置一个模板,使其为abstract="true"
spring中bean 的继承 在java 类中称为继承 在spring称为模板
<2.1>代理定义 定义模板(父类)
<bean id="baseTxProxy" lazy-init="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<2.2> 为不同的dao操作类加上事务
<!-- 给dao1加事务-->
<bean id="daotran1" parent="baseTxProxy"> <!-- baseTxProxy为刚刚配置的模板-->
<property name="target">
<ref local="dao1"/>
</property>
</bean>
<!-- 给dao2加事务-->
<bean id="daotran2" parent="baseTxProxy">
<property name="target">
<ref local="dao2"/>
</property>
</bean>
<3>使用拦截器
<3.1>定义事务拦截器 org.springframework.transaction.interceptor.TransactionInterceptor
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 配置事务管理器 引用上面配置的来注入 -->
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<3.2> 定义代理 bean 采用自动代理 BeanNameAutoProxyCreator (前面讲过有例子)
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*dao</value> <!-- dao bean id匹配 -->
</list>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value> <!-- 引用事务拦截器 -->
</list>
</property>
</bean>
13 spring与struts的整合
整合中要思考的是:怎样才能加载和实例化spring容器.先把spring容器放到web容器中,然后再根据一些方法去提取,
13.1 在Strust1中直接使用spring
让我们回顾一下前面所讲的如何在web环境中使用spring,
根据servlet版本的不用,我们可以通过在web.xml里配置servlet或者监听器来实例化spring容器,
1.在web.xml中配置
①.加载spring 容器
<!-- 加载spring 容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/beans.xml</param-value>
</context-param>
②.实例化spring 容器
<!-- 初始化spring容器方法一 servlet版本 前面有讲述-->
<servlet>
<servlet-name>contextLoader</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<!-- 初始化spring容器方法二 监听器版 前面有讲述-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
之后就可以通过WebApplicationContextUtils取得Spring的上下文
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(当前ServletContext);
如在struts1中,必须知道当前的servlet上下文
①WebApplicationContext ctx=WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
②WebApplicationContext beanFactory=WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());
如在struts2中
WebApplicationContext ctx=WebApplicationContextUtils.getWebApplicationContext(ServletActionContext.getServletContext());
有了WebApplicationContext实例,我们就可以通过getBean方法获得spring容器中的bean了,如下所示
13.2 Strust1整合Spring的其他3种方式
在上面的Strust1中直接使用Spring,我们是通过在web.xml中配置servlet或者是listener加载和实例化spring容器。实则上
spring提供了一种专门针对于struts的插件来加载和实例化spring容器,只需在struts-config.xml加入即可,
所以我们如果不想用前面的来加载可以使用下面的
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="/WEB-INF/classes/applicationContext.xml" />
</plug-in>
<!--
注意 /WEB-INF/classes/applicationContext.xml这个位置,如果你的文件在WEB-INF。则写成/WEB-INF/applicationContext.xml
在eclipse 中 /WEB-INF/classes/applicationContext.xml对应的目录是src目录,applicationContext.xml放在src下
-->
◆使用Spring的ActionSupport类整合Structs
优点:
1) 简单
缺点:
1) 耦合高 它将Struts动作与Spring框架耦合在一起。如果您想替换掉Spring,那么您必须重写代码
2) 违反IOC
3) 无法使用 DispatchAction
◆使用Spring的DelegatingRequestProcessor覆盖Struts的RequestProcessor
DelegatingRequestProcessor方法的确比第一种方法好,缺点 RequestProcessor如果改变了怎么办或者是有不同的RequestProcessor怎么办呢
◆将Struts Action管理委托给Spring框架
动作委托解决方法是这三种方法中最好的。Struts动作不了解Spring,不对代码作任何改变就可用于非Spring应用程序中。RequestProcessor的改变不会影响它,并且它可以利用Spring AOP特性的优点。
优点
1. 动作委托解决方法是这三种方法中最好的。
2. 不使用Spring api编写 Action
3. 利用了IOC装配
三种方式的相关配置:
<1> Action直接继承ActionSupport,在Action类的execute()方法中通过
ApplicationContext ctx=getWebApplicationContext()获得Spring的
上下文,通过上下文获取相应的bean实例
<2>覆盖RequestProcessor
1.在struts-config.xml中配置控制器
<controller processorClass="org.springframework.web.struts.DelegatingRequestProcessor"/>
2.在applicationContext.xml文件中注册action动作bean
<bean name="/struts-config.xml配置的对应action的path" class="Action类的包名类名" >
<!--注意上面的是name而不是大家经常写的id-->
<property name="service">
<ref bean="service" /> <!--注入spring实例,假设属性名为service-->
</property>
</bean>
3.Action类中声明一个Service私有属性及其setter方法,通过IOC注入Service实例。
<3>动作管理委托给Spring
1.struts-config.xml中action标签内的type属性值替换为org.springframework.web.struts.DelegatingActionProxy,如下
<action input="/index.jsp" path="/hello" scope="session"
type="org.springframework.web.struts.DelegatingActionProxy">
<forward name="success" path="/success.jsp" />
</action>
2.在applicationContext.xml文件中注册action动作bean
<bean name="/struts-config.xml配置的对应action的path" class="Action类的包名.类名" >
<property name="service">
<ref bean="service" />
</property>
</bean>
3.Action类中声明一个Service私有属性及其setter方法,通过IOC注入Service实例
13.2 Spring与Struts2的整合
由于Struts2得强大可插拔式设计,使得整合spring的工作变得异常简单,struts2-spring-plugin-2.0.8.jar就是支持spring的插件包
0.把struts2支持spring的插件包jar拷贝到项目中
1.web.xml的配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- 监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 定义Struts2的FilterDispathcer的Filter -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<!-- FilterDispatcher用来初始化struts2并且处理所有的WEB请求。 -->
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
2.applicationContext.xml的配置(WEB-INF目录下)
(如果不使用默认的 则可以在web.xml通过以下配置修改xml的配置以及名称)
<!-- 加载spring 容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/beans.xml</param-value>
</context-param>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-2.5.xsd">
<bean name="service" class="com.service.impl.ServiceImpl"/>
<!-- action的配置 -->
<bean name="abc" class="com.LoginAction" >
<property name="service">
<ref bean="service" /> <!--注入spring实例,假设action类中有一个属性名为service-->
</property>
</bean>
</beans>
3.struts.xml的配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<include file="struts-default.xml" />
<package name="default" extends="struts-default">
<!-- action标签中的class属性与applicationContext.xml中的action的bean的name属性一致 如以下的abc -->
<action name="login" class="abc">
<result name="input" >/login.jsp</result>
<result name="success">/welcome.jsp</result>
<result name="error">/failed.jsp</result>
</action>
</package>
</struts>
4.action类中声明service的一个变量及setter方法
14 Spring2.5有哪些改进
Spring2.5rc1发布了,一直想知道它葫芦里卖什么药
1 spring bean的作用域 已经有原来的单例和非单例 变成了5个
2 Jar 包:一个包分解成多个包 如 SpringMVC 不再使用spring.jar 这个庞大的包了。 Spring-webmvc.jar, spring-webmvc-portlet.jar 可以在 lib/modules 目录下找到,而且对于Struts1.* 的支持的包也应该改成 spring-webmvc-struts.jar了。
3 Hibernate:注意Spring已经不再支持Hibernate 3.1之前的版本了,也就是说2.1,3.0的版本也无法使用了。如果仍然要用的话,推荐使用Spring的2.0.6/2.0.7版本。
4. JDK版本: JDK至少要1.4.2以上,如果仍然打算使用1.3的话就请用2.0.6/2.0.7版本吧。
5. XML配置:推荐使用XML metadata格式,不过先前的DTD仍然支持。需要注意的一点是,Spring2.0的DTD继续使用“singleton”属性,但是新的Spring2.5 DTD不允许使用“singleton”属性了,改成“scope”属性来描述bean的生命周期。
6. 废弃的类与方法:有些在先前版本标注过“@deprecated”的类与方法已经完全被废弃了。
比如:
1.
ResultReader : 被 RowMapper 接口取代。
2.
BeanFactoryBootstrap : 考虑使用 BeanFactoryLocator 或自定义的bootstrap类来代替。
7. Apache OJB:注意Spring源代码中已经完全把这个去掉了,但与之整合的类仍然可以在Spring Modules project找到。https://springmodules.dev.java.net/
8. iBATIS:注意Spring已经不再支持iBATIS 的1.3版本了, 如果想继续的话,请升级到2.3以上吧。
9. JDO:注意Spring已经不支持JDO1.0了。同样,你可以升级到2.0以上版本,或者使用Spring的2.0.6/2.0.7版本。
10. UrlFilenameViewController:这个东东我也没有接触过,这里,我就简单翻译一下吧。
“考虑到嵌套路径的请求,视图名称现在决定叫UrlFilenameViewController了,这是一个突破性的改变,并且意味着如果你从Spring1.* 升级到Spring2.0 你可以使用该类从而减少Spring Web MVC的配置工作。”
15 spring 注解
<一> 1 @Autowired 2 @Autowired
@Qualifier("bean名称")
需要<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<二> JSR-250 的注释 @Resource @PostConstruct 和 @PreDestroy
加入common-annotations.jar包
需要<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
可用 <context:annotation-config/>。简化第一和第二的配置 请看下面的配置:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config/>
<bean id="chinese" class="com.Chinese"></bean>
<bean id="American" class="com.American"></bean>
<bean id="test" class="com.Test"></bean>
</beans>
<三> @Component
Component或者@Component("bean名") @Component默认bean名为类名 首字母小写
不需要配置bean 配置文件如下
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="com"/> <!--com包 这里改成你的包名-->
</beans>
以下是具体说明 高手可掠过
Spring 通过一个 BeanPostProcessor 对 注解进行解析,所以要让 注解 起作用必须事先在 Spring 容器中声明 AutowiredAnnotationBeanPostProcessor Bean。
如下
<!-- 该 BeanPostProcessor 将自动起作用,对标注 @Autowired 的 Bean 进行自动注入 -->
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
15.1 Spring 2.5 引入了 @Autowired 注解,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作,按照类型进行装配
如
@Autowired
public void setP(Person p) {
this.p = p;
}
15.2 当不存在不匹配的bean或者是匹配的bean的数目大于1时,按照类型进行装配都会报出异常,可采用以下方式不报都会报出异常
@Autowired(required = false)
15.3 采用以下方式指定bean,按名字匹配
@Autowired
@Qualifier("bean名称")
用在构造方法上
@Autowired
public Test(@Qualifier("chinese")Person p) {
// TODO Auto-generated constructor stub
this.p=p;
}
15.3 使用 JSR-250 的注释 @Resource @PostConstruct 和 @PreDestroy
Spring 不但支持自己定义的 @Autowired 的注释,还支持几个由 JSR-250 规范定义的注释,它们分别是 @Resource、@PostConstruct 以及 @PreDestroy。
为了让 JSR-250 的注释生效,除了在 Bean 类中标注这些注释外,还需要在 Spring 容器中注册一个负责处理这些注释的 BeanPostProcessor:
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
@Resource
@Resource 的作用相当于 @Autowired,只不过 @Autowired 按 byType 自动注入,面 @Resource 默认按 byName 自动注入罢了。@Resource 有两个属性是比较重要的,分别是 name 和 type,Spring 将 @Resource 注释的 name 属性解析为 Bean 的名字,而 type 属性则解析为 Bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。
Resource 注释类位于 Spring 发布包的 lib/j2ee/common-annotations.jar 类包中,因此在使用之前必须将其加入到项目的类库中。
JSR-250 为初始化之后/销毁之前方法的指定定义了两个注释类,分别是 @PostConstruct 和 @PreDestroy,这两个注释只能应用于方法上。标注了 @PostConstruct 注释的方法将在类实例化后调用,而标注了 @PreDestroy 的方法将在类销毁之前调用。
使用 <context:annotation-config/> 简化配置
而我们前面所介绍的 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 就是处理这些注释元数据的处理器。但是直接在 Spring 配置文件中定义这些 Bean 显得比较笨拙。Spring 为我们提供了一种方便的注册这些 BeanPostProcessor 的方式,这就是
<context:annotation-config/>。请看下面的配置:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config/>
<bean id="chinese" class="com.Chinese"></bean>
<bean id="American" class="com.American"></bean>
<bean id="test" class="com.Test"></bean>
</beans>
<context:annotationconfig/> 将隐式地向 Spring 容器注册 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor 以及 equiredAnnotationBeanPostProcessor 这 4 个 BeanPostProcessor。
15.4 使用 @Component或者@Component("bean名") @Component默认bean名为类名 首字母小写
然我们可以通过 @Autowired 或 @Resource 在 Bean 类中使用自动注入功能,但是 Bean 还是在 XML 文件中通过 <bean> 进行定义 —— 也就是说,在 XML 配置文件中定义 Bean,通过 @Autowired 或 @Resource 为 Bean 的成员变量、方法入参或构造函数入参提供自动注入的功能。能否也通过注释定义 Bean,从 XML 配置文件中完全移除 Bean 定义的配置呢?答案是肯定的,我们通过 Spring 2.5 提供的 @Component 注释就可以达到这个目标了。
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="com"/><!--com包-->
</beans>
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架.
spring的设计思想是,单例模式和工厂模式
2 spring的四大特点(优点)
轻量级,低侵入的设计
Spring的DI机制降低了业务对象替换的复杂性
spring不依赖于web容器,独立于各种应用服务器, Write Once,Run Anywhere(一次编译到处运行)
高度开放性:Spring并不完全依赖于Spring,开发者可自由选用Spring框架的部分或全部,它的架构仍然是内在稳定的
3 spring的组成部分 七大模块
Spring Core:Spring的基石,提供了Spring的最主要的核心机制:控制反转和依赖注入
Spring Context:提供了Spring的上下文信息,如:国际化,验证等
Spring Web支持:简化了处理多部分请求
Spring MVC框架支持:一个全功能的构建 Web 应用程序的 MVC 实现,MVC 容纳了大量视图技术,其中包括 JSP、Velocity等。
Spring Dao支持:Spring的Dao支持大大的简化了JDBC操作数据库所带来的繁琐
Spring ORM支持 pring框架集成了若干ORM框架,从而提供了ORM的对象关系工具,其中包括 JDO、Hibernate、iBatis和TopLink。
所有这些都遵从Spring的通用事务和DAO异常层结构。
Spring AOP:面向方面编程,提供了事务,日志,权限,安全等处理机制
具体解释
Spring 核心容器(Core):提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,它
是工厂模式的实现。BeanFactory使用控制反转(Ioc)模式将应用程序的配置和依赖性规范与实际的应
用代码程序分开。
Spring AOP:通过配置管理特性,Spring AOP模块直接面向方面的编程功能集成到了Spring框架中,所以可以很容易的使Spring框架管理的任何对象支持 AOP。Spring AOP模块为基于Spring的应用程序
中的对象提供了事务管理服务。通过使用Spring AOP,不用依赖于EJB组件,就可以将声明性事务管理
集成到应用程序中。
Spring ORM:Spring框架集成了若干ORM框架,从而提供了ORM的对象关系工具,其中包括 JDO、Hibernate、iBatis和TopLink。所有这些都遵从Spring的通用事务和DAO异常层结构。
Spring DAO:JDBC DAO抽象层提供了有意义的异常层次的结构,可用该结构来管理异常处理和不同数据供应商抛出的异常错误信息。异常层次结构简化了错误处理,并且大大的降低 了需要编写的异常代码数量(例如,打开和关系连接)。Spring DAO的面向JDBC的异常遵从通用的DAO异常层结构。
Spring WEB:Web上下文模块建立在上下文模块(Context)的基础之上,为基于Web服务的应用
程序提供了上下文的服务。所以Spring框架支持 Jakarta Struts的集成。Web模块还简化了处理多部分请求
及将请求参数绑定到域对象的工作
Spring上下文(Context):Spring上下文是一个配置文件,向Spring框架提供上下文信息。
Spring上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化校验和调度功能。
Spring MVC:Spring的MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,
MVC框架变成为高度可配置的,MVC容纳的大量视图技术,包括JSP、Velocity、Tiles、iText和Pol
4 spring的核心机制
1).控制反转(IoC/Inverse Of Control):调用者不再创建被调用者的实例,由spring框架实现(容器创建)所以称为控制反转。
2).依赖注入(DI/Dependence injection) :创建好实例后再注入调用者称为依赖注入。
当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,
在传统的程序设计过程中,通常由调用者来创建被调用者的实例, 但在Spring里,创建被调用者的工
作不再由调用者来完成,因此称为控制反转; 创建被调用者 实例的工作通常由Spring容器来完成,
然后注入调用者,因此也称为依赖注入
什么是ioc容器
bean工厂(BeanFactory) 和 应用上下文(Application Context)
在Spring中,BeanFactory是IoC容器的核心接口。 它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
BeanFactory
|
|
ApplicationContext(国际化)
/ \
/ \
FileSystemXmlApplicationContext ClassPathXmlApplicationContext
常用有三种方式可以得到BeanFactory ,从而bean实例,并进行调用
// InputStream is = new FileInputStream("beans.xml");
// InputStreamResource isr = new InputStreamResource(is);
// BeanFactory beanFactory = new XmlBeanFactory(isr);
//
// Spring给出一些BeanFactory的实现类,其中最为常用的是XmlBeanFactory。
// 1、通过文件系统
// Resource res = new FileSystemResource("src/beans.xml");
// XmlBeanFactory beanFactory = new XmlBeanFactory(res);
// 2、通过类路径(class路径 ./表示上级目录)
// ClassPathResource res = new ClassPathResource("./beans.xml");
// XmlBeanFactory beanFactory = new XmlBeanFactory(res);
// 3、通过ApplicationContext加载(ClassPathXmlApplicationContext或者FileSystemXmlApplicationContext)
// ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
// new String[] {"./beans.xml"});
// BeanFactory beanFactory = (BeanFactory) appContext;
//
// ClassPathResource res = new ClassPathResource("./beans.xml");
// XmlBeanFactory beanFactory = new XmlBeanFactory(res);
或者 ApplicationContext ctx=new FileSystemXmlApplicationContext("src/bean.xml");
ApplicationContext增加功能 1国际化2事件支持
国际化测试
(1)bean配置
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>message</value>
<!-- 如果有多个资源文件,全部列在此处-->
</list>
</property>
</bean>
(2)
ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
String[] a = {"读者"};
String hello = ctx.getMessage("hello",a,Locale.ENGLISH);//英文
Object[] b = {new Date()};
String now = ctx.getMessage("hello",b,Locale.getDefault());//默认
System.out.println(hello);
System.out.println(now);
5 简单测试BeanFactory
<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="aaa" class="包名.类名"/>
</beans>
测试 FileSystemXmlApplicationContext默认从项目目录寻找bean配置文件xml
ApplicationContext ctx = new FileSystemXmlApplicationContext("src/bean.xml");
Test t=(Test)ctx.getBean("aaa");
System.out.println(t.getName());
依赖注入的优点,代码将更加清晰,Spring管理bean的灵巧性, bean与bean之间的依赖关系放在配置文件里组织,
不再担心对象之间的依赖关系之后,实现更高层次的松耦合将易如反掌
依赖注入的方式 (为什么叫依赖注入 类的四种关系 )
(1)set注入(2)构造注入(3)lookup方法注入
setter注入实例
<bean id="aaa" class="包名.类名">
<property name="属性名">
<ref local="另一个bean id"/>//local与bean的区别
</property>
</bean>
//local与bean的区别 local:当前xml bean:整个spring容器
构造注入实例 提供构造方法(注入的实例参数) 要提供无参的构造方法
<bean id="aaa" class="包名.类名">
<constructor-arg><ref bean="steelAxe"/></constructor-arg>
</bean>
(3)lookup方法注入(依赖注入的bean每次都创建一个新实例)
这种方法主要是用在Singleton的Object中使用非Singleton的Bean时,
通过lookup-method的那个方法来取得非Singleton的Bean。一般用的不多,在用这种定义之前最佳想明白你的需求。
1 Singleton的Object 中提供一个抽象方法,返回非Singleton的Bean,此时Singleton的类变成抽象类 如
public abstract class Test//Singleton的Bean {
TestBean tb;//非Singleton的Bean时
public TestBean getTb() {
return tb;
}
public void setTb(TestBean tb) {
this.tb = tb;
}
public abstract TestBean createXxx();
}
2 配置xml
<bean id="testbean" class="com.TestBean" singleton="false"/>//注意singleton="false"
<bean id="test" class="com.Test">
<property name="tb"> <ref local="testbean"/></property>//注意这个依然不能少
<lookup-method name="createXxx" bean="testbean"/>
</bean>
3 测试
Test t=(Test)ctx.getBean("test");
System.out.println("不使用lookup-method注入");
TestBean tb1=t.getTb();
TestBean tb2=t.getTb();
System.out.println(tb1==tb2);
System.out.println("使用lookup-method注入");
TestBean tb3=t.createXxx();
TestBean tb4=t.createXxx();
System.out.println(tb3==tb4);
结果
不使用lookup-method注入
true
使用lookup-method注入
false
注入其他属性例子
<beans>
<bean id="aaa" class="包名.类名"/>
<bean id="bbb" class="lee.Chinese">
<property name="schools">
<list>
<value>小学</value>
<value>中学</value>
<value>大学</value>
</list>
</property>
<property name="score">
<map>
<entry key="数学">
<value>87</value>
</entry>
<entry key="英语">
<value>89</value>
</entry>
<entry key="语文">
<value>82</value>
</entry>
</map>
</property>
<property name="health">
<props>
<prop key="血压">正常</prop>
<prop key="身高">175</prop>
</props>
</property>
<property name="axes">
<set>
<value>xxx</value>
<bean class="包名.类名"/>
<ref local="另外一个bean id"/>
</set>
</property>
</bean>
</beans>
上述中的health指的是Properties属性类
private Properties health = new Properties();
测试 Spring的DI机制降低了业务对象替换的复杂性 面向接口编程的好处 灵活配置
6 spring bean的实例 创建的几种方式
(1)构造器 单例思想
(2)静态工厂(静态方法创建)
静态方法名(iint type)
<bean id="xxx" class="包名.类名(工厂类)" factory-method="静态方法名">
<constructor-arg value="1"></constructor-arg>
</bean>
创建同一接口下不同实例
(3)工厂方法(非静态方法创建)
<bean id="aaa" class="com.PersonFactory(工厂类)">
<property name="type"><value>1</value></property>
</bean>
<bean id="xxx" factory-bean="工厂bean id" factory-method="非静态方法名">
7 自动装配
有两个bean A与B
B作为A的一个属性,当我们没有通过setter注入或者构造注入B实例时,我们可以在A bean中指定autowire属性,
让它在spring容器个根据不同方式自动寻找b实例
自动装配的优缺点:
优点:自动装配能显著减少配置的数量,自动装配可以使配置与java代码同步更新
缺点:Spring会尽量避免在装配不明确的时候进行猜测,容器中可能存在多个bean定义跟自动装配的
setter方法和构造器参数类型匹配
byName(用于set注入) 根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。例如,在bean定义中将autowire设置为by name,而该bean包含master属性(同时提供setMaster(..)方法),Spring就会查找名为master的bean定义,并用它来装配给master属性。
byType 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配。若没有找到相匹配的bean,则什么事都不发生,属性也不会被设置。如果你不希望这样,那么可以通过设置dependency-check="objects"让Spring抛出异常。
constructor 与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
autodetect 通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。
在用byType时候,如果没有匹配的bean 可测试dependency-check="objects"让Spring抛出异常
8 spring框架中bean的生命周期?
(1) bean定义
在配置文件里面用<bean></bean>来进行定义。
(2) bean初始化
有两种方式初始化: 也可同时使用。参数指定的后执行
A.在配置文件中通过指定init-method属性来完成
B.实现org.springframwork.beans.factory.InitializingBean接口 实现afterPropertiesSet()方法
(3) bean调用
有三种方式可以得到bean实例,并进行调用
(4) bean销毁
销毁有两种方式。也可同时使用参数指定的销毁方法后运行
A.使用配置文件指定的destroy-method属性
B.实现org.springframwork.bean.factory.DisposableBean接口 实现destroy()方法
可以通过调用ConfigurableListableBeanFactory(XmlBeanFactory)里的destroySingletons销毁单例对象,测试destroy()方
ConfigurableListableBeanFactory beanFactory =
new XmlBeanFactory(new FileSystemResource("src/bean.xml"));
beanFactory.destroySingletons();
}
是的, 当调用beanFactory.destroySingletons()方法的时候,bean不会马上销毁,但是容器在销毁bean之前,会等到方法结束剩余的任务后
再调用相应的销毁bean之前指定的其他方法。再干掉bean
在 spring 2.5中 ((AbstractApplicationContext)beanFactory).registerShutdownHook();来看看bean的销毁
原型 bean 在创建后即脱离 BeanFactory 的维护,所以只能调用初始化方法,而不能做清理工作。
如果不是Singleton的Bean不能触发结束初始化事件和预销毁事件么?那是因为如果不是单例模式的Bean,Spring不会自己去管理,而是把它们交给Spring框架下的应用本身去管理,这样就相当于把Bean交给了GC。但是如果是单例模式的Bean,Spring会建立一个Bean的列表来统一管理,在Spring应用被关闭的时候,会执行BeanFactory中的destroySingltons()方法来逐个销毁列表中的Bean。这就是为什么只有单例模式实现Spring的那两个事件接口或指定方法属性才是有效的
可以考虑引入bean的后处理技术
9 spring 中bean的作用域(5种):2.0以前只有单例和非单例 2。0以后有以下5种
singleton
在每个Spring IoC容器中一个bean定义对应一个对象实例。
prototype
一个bean定义对应多个对象实例。
request
在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例, 它们依
据某个bean定义创建而成。该作用 域仅在基于web的Spring ApplicationContext情形下有效。
session
在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring
ApplicationContext情形下有效。
global session
在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet
context的时候有效。该作用域仅在基于 web的Spring ApplicationContext情形下有效。
10 spring在web环境中的配置(2种)
1.在Web.xml中配置上下文载入器
根据你的系统情况,你可以选择两种上下文载入器:ContextLoaderListener和ContextLoaderServlet.
如果你的Web容器支持Servlet2.3标准或更高,你可以使用两者,否则只能使用后者.
(1)ContextLoaderListener在Web.xml应该如下配置:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
(2)ContextLoaderServlet在Web.xml应该如下配置:
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>
org.springframework.web.context.ContextLoaderServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
2.指定上下文载入器的配置文件
不论你使用的那种上下文载入器,你都应该指明Spring配置文件的位置.如果没有指定,上下文载入器将把/web-inf/applicationContext.xml当作Spring配置文件。
要指定Spring配置文件的位置,你可以在Servlet上下文设置contextConfigLocation参数来为上下文载入器指定一个或多个Spring配置文件
(使用通配符或是用逗号隔开)。如下所示:
<context-param>
<param-name>
contextConfigLocation
</param-name>
<param-value>
/WEB-INF/bean.xml
</param-value>
</context-param>
3.获得应用上下文
接下来我们就可以获得ApplicationContext了,代码如下:
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
在一个自启动的Servlet中,我们可以这样获得它:
public class InitialSystemServlet extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
// 取得Spring的上下文
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());
}
测试web应用环境相关的Bean作用域
spring 2.5 dtd配置
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-2.5.xsd">
<bean id="test" class="com.Test" >
</bean>
</beans>
如果用户使用spring的webApplicationContext,则可以使用另外3种Bean的作用域:request,session和globalSession.不过
在使用这些作用域之前,首先必须在web容器中进行一些额外的配置,在高版本的web容器中,则可以利用HTTP请求监听器进行配置:
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
细心的同学可能有一个疑问:在介绍webApplicationContext初始化时,我们已经通过ContextLoaderListener将web容器与
spring容器整合,为什么这里又要引入一个额外的RequestContextListener以支持Bean的另外3个作用域呢?
在整合spring容器时使用ContextLoaderListener,它实现了ServletContextListener监听器接口,ServletContextListener
只负责监听web容器启动和关闭的事件.而RequestContextListener实现ServletRequestListener监听器接口,该监听器监听
HTTP请求事件,web服务器接收的每一次请求都会通知该监听器.
spring容器启动和关闭操作由web容器的启动和关闭事件触发,但如果spring容器中的Bean需要request,session,globalsession
作用域的支持,spring容器本身就必须获得web容器的HTTP请求事件,以HTTP请求的事件"驱动"Bean作用域的控制逻辑.
11 spring 对dao的支持
<1>dao模式优点
减少开发代码量 提高工作效率
降低系统资源消耗 提高系统性能
业务逻辑层与持久层(数据层)的分离,使数据与操作更为清晰。
数据访问独立到了一层,修改具体实现类,不影响系统的架构运行
<2>DAO模式的四个组件
DAO接口
DAO接口实现类
pojo值对象
DAO实例的定位(工厂 或 spring注入)
2. 核心类
JdbcTemplate(需要注入DataSource)
JdbcDaoSupport类(简化注入,有一个字段dataSource)
并提供了getJdbcTemplate()方法获得JdbcTemplate实例
DataSource接口
为了从数据库中取得数据,我们首先需要获取一个数据库连接。Spring通过DataSource对象来完成这个工作。
DataSource是JDBC规范的一部分,它被视为一个通用的数据库连接工厂。通过使用DataSource,
Container或Framework可以将连接池以及事务管理的细节从应用代码中分离出来。
作为一个开发人员,在开发和测试产品的过程中,你可能需要知道连接数据库的细节。
但在产品实施时,你不需要知道这些细节。通常数据库管理员会帮你设置好数据源。
在使用Spring JDBC时,你既可以通过JNDI获得数据源,也可以自行配置数据源(使用Spring提供的DataSource实现类)。
使用后者可以更方便的脱离Web容器来进行单元测试。 这里我们将使用DriverManagerDataSource
,不过DataSource有多种实现, 后面我们会讲到。使用DriverManagerDataSource和你以前获取一个JDBC连接 的做法没什么两样。
你首先必须指定JDBC驱动程序的全限定名,这样DriverManager 才能加载JDBC驱动类,接着你必须提供一个url(因JDBC驱动而异,
为了保证设置正确请参考相关JDBC驱动的文档), 最后你必须提供一个用户连接数据库的用户名和密码。
目前已经有开源的免费用了
DataSource
/ \
/ \
DriverManagerDataSource org.apache.commons.dbcp.BasicDataSource
下面我们将通过一个例子来说明如何配置一个 DataSource ,
1 自己实现DataSource接口,设置数据库相关连接信息
2 使用现有的实现类dataSource 编程方式 获得dataSourc 如下
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver<");
dataSource.setUrl("jdbc:mysql://localhost:3306/j2ee");
dataSource.setUsername("root");
dataSource.setPassword("123456");
3 通过开源dbcp获得dataSource ,spring方式
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/j2ee</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>123456</value>
</property>
</bean>
使用Spring的Dao支持来写Dao层,继承JdbcDaoSupport类,JdbcDaoSupport类中有一个字段dataSource
也就是数据库连接,因此只需继承JdbcDaoSupport类,并给它注入dataSource,就隐式的获得了数据库连接,可以在bean.xml文件中
注入connection(即:dataSource)
<beans>
<!-- spring 方式获得dataSource-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/j2ee</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>123456</value>
</property>
</bean>
<bean id="xxx" class="包名.类名(dao的实现类)">
<property name="dataSource">
<ref local="dataSource"/>
</property>
</bean>
</beans>
3.在这个Dao 实现类中写一个内部类,使其实现:RowMapper接口,用来封装成具体的pojo对象,代码如下
private class PersonRowMapper implements RowMapper
{
public Object mapRow(ResultSet resultSet, int rowNumber)
throws SQLException {
User user = new User();
user.setId(resultSet.getLong("id"));
user.setName(resultSet.getString("name"));
user.setSex(resultSet.getString("sex"));
user.setAge(resultSet.getInt("age"));
user.setAddr(resultSet.getString("addr"));
return user;
}
}
4 通过JdbcTemplate类进行增删查询修改操作
(1)增加 修改 删除示例
public void createPerson(PersonBean p)
{
Object[] args = {p.getName() , new Integer(p.getAge()) };
getJdbcTemplate().update("insert into person_test(p_name,p_age) values(?,?)", args );
}
(2)查询 返回单个object
public PersonBean getPerson(int id)
{
Object[] args = {new Integer(id)};
//PersonRowMapper是刚刚的内部类
return (PersonBean)getJdbcTemplate().queryForObject("select p_name,p_age from person_test where p_id = ?", args, new PersonRowMapper());
}
(3)返回list
public List findPersonsByName(String name)
{
//PersonRowMapper是刚刚的内部类
return getJdbcTemplate().query("select * from person_test where p_name like '%" + name +"%'" , new PersonRowMapper());
}
5 spring 2.5以后提供了一个SimpleJdbcTemplate类来操作
2.5例子
public class PersonDaoSpring25 implements PersonDao {
private SimpleJdbcTemplate simpleJdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
}
@Override
public void add(Person p) {
// TODO Auto-generated method stub
String sql = "insert into person(name) values(?)";
simpleJdbcTemplate.update(sql, p.getName());
}
@Override
public void del(String id) {
// TODO Auto-generated method stub
String sql="delete from person where id=?";
simpleJdbcTemplate.update(sql, id);
}
@Override
public List findAll() {
// TODO Auto-generated method stub
String sql = "select * from person";
List list = simpleJdbcTemplate.getJdbcOperations().query(sql,
new BeanPropertyRowMapper(Person.class));
return list;
}
@Override
public Person findById(String id) {
String sql = "select * from person where id=?";
Person p = simpleJdbcTemplate.queryForObject(sql,
ParameterizedBeanPropertyRowMapper.newInstance(Person.class),
id);
return p;
}
@Override
public void update(Person p) {
String sql = "update person set name=? where s_id=?";
simpleJdbcTemplate.update(sql, p.getName(), p.getId());
}
}
12 spring aop
AOP的好处:
消除了编码模块之间的依赖
可以在任意阶段,向已有功能模块中填加新功能,且不侵入原有功能
AOP的特征:
各步骤之间的良好隔离性 , 源代码的无关性
Spring 面向方面编程(AOP) spring支持AOP功能,AspectJ更完美的支持AOP
AOP 的核心构造是方面,它将那些影响多个类的行为封装到可重用的模块中, 将系统中通用的需求功能隔离出来形成一个功能模块,
并将这个模块切入到应用程序当中, AOP追求的是调用者与被调用者的解耦,从而消除了OOP引起的代码混乱和分散问题,
增强了系统的可维护性和代码的重用性
方面:哪方面 系统中分为业务方面的和非业务方面 Spring主要集中于非业务方面 如(日志、事务、安全、权限等)
1.面向方面与面向切面:AOP的实现中的几个重要的概念:
1.1如果理解为“面向方面编程”:
针对于某一模块进行专门的编写(如:面向日志编程,面向事务编程,面向权限等),其意思就是说面向具体的某个功能模块来编程,然后将其切入到项目中
1.2如果理解为“面向切面编程”:
连接点:程序执行过程中明确的点,如方法的调用或者异常的抛出,举个例子,如果是一个权限系统的话,要控制到类中的某一个具体的方法,那么这个方法就是一个连接点
切入点:连接点的集合,如类中多个个方法的调用, 还是以权限系统来举例,如果要控制一个类中的多个方法的话,那么这几个方法(也即是几个连接点)组成了一个切入点
切面:如果要控制多个类中的多个方法,那么这多个类就组成了一个切面
连接点 --- 切入点 ---- 切面(三者之间的关系可以形象的理解为:点--线--面)
2.1.连接点 --- 切入点 ---- 切面 --- 方面(解决方案的切入点)
2.2.目标对象(也就是:寻找被处理的类)
2.3.AOP代理(具体实现),分为二种,
JDK动态代理(面向接口)
Cglib代理(面向具体类)
2.4.处理(Spring AOP处理)或者叫通知,aop框架在特定的连接点执行的动作,Spring提供了五种处理方式
2.5 Advisor=(处理+切入点)
2.6 下面介绍Spring的处理
实现步骤
(1)目标对象定义 bean定义
(2) 处理与Advisor
<1> 处理 定义(1 在哪里处理<连接点 --- 切入点 ---- 切面 --- 方面> 2什么方式处理<如前处理,后处理,前后都处理>)
如果只是简单的定义处理,则默认的切入点是目标类的所有方法都处理
<2> 如果希望更精确的切入点,则可以采用Advisor(切入点+处理),以下是采用正则表达式支持类RegexpMethodPointcutAdvisor的示例
配置Advisor (Advisor=切入点+通知)
<bean id="testAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!-- advice属性确定处理bean-->
<property name="advice">
<!-- 此处的处理bean定义采用嵌套bean,也可引用容器的另一个bean-->
<bean class="包名.通知bean类名" />
</property>
<!-- patterns确定正则表达式模式-->
<property name="patterns">
<list>
<!-- 确定正则表达式列表-->
<value>.*say.*</value> <!-- 业务实现方法名匹配 -->
</list>
</property>
</bean>
(3) aop代理对象定义 bean 定义
<0>手写aop代理(编程式)
<1>采用ProxyFactoryBean生成代理
特点:一种接口或者一个类 都需要对应的一个具体代理,需要指定接口或者类 以及对应的代理定义
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--当用面向具体类实现时 proxyInterfaces属性可以不用注入 此时采用Cglib代理,必须加入Cglib的jar包 -->
<property name="proxyInterfaces">
<value>包名.目标对象的接口</value>
</property>
<property name="target">
<ref local="目标对象的bean id"/>
</property>
<property name="interceptorNames">
<list>
<value>处理bean id</value><!-- list说明可以注入多个处理 -->
</list>
</property>
</bean>
<2> 自动代理 主要采用了 bean的后处理技术 实现了bean的后处理接口BeanPostProcessor,通常有两个常用的实现类
在spring bean 的生命周期中,可以在bean创建之后(如指定init-method),销毁之前(指定distory-method),让容器
执行特定的方法,如果有更多的方法,需要在创建之时(注意是创建之时)被调用,可采用实现BeanPostProcessor接口
使用BeanPostProcessor,让我们的bean实现BeanPostProcessor接口
1 public class Chinese implements Person,BeanPostProcessor{
@Override
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("你好");
}
@Override
public Object postProcessAfterInitialization(Object arg0, String arg1)
throws BeansException {
// TODO Auto-generated method stub
System.out.println("进入postProcessAfterInitialization方法");
System.out.println(arg1);//返回之前可以包装一下
return arg0;
}
@Override
public Object postProcessBeforeInitialization(Object arg0, String arg1)
throws BeansException {
// TODO Auto-generated method stub
System.out.println("进入postProcessBeforeInitialization方法");
System.out.println(arg1);//返回之前可以包装一下
return arg0;
}
}
2 客户端调用
Resource res = new FileSystemResource("src/beans.xml");
XmlBeanFactory beanFactory = new XmlBeanFactory(res);
Chinese c = new Chinese();
beanFactory.addBeanPostProcessor(c);//注意这句哦,注册BeanPostProcessor
Person p = (Person)beanFactory.getBean("chinese");
spring为我们提供了以下两种实现
BeanPostProcessor
/ \
/ \
BeanNameAutoProxyCreator DefaultAdvisorAutoProxyCreator
<2.1> 采用BeanNameAutoProxyCreator自动生成代理
特点:多种接口或者多个类 自动创建其对应代理,需要指定接口或者类。接口或者类共用一个自动代理
<!-- 定义BeanNameAutoProxyCreator-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!-- 指定对满足哪些bean name的bean自动生成业务代理 -->
<property name="beanNames">
<!-- 下面是所有需要自动创建代理的bean-->
<list>
<value>bean id 1</value>
<value>bean id 2</value>
</list>
</property>
<!-- 下面定义BeanNameAutoProxyCreator所需的处理-->
<property name="interceptorNames">
<list>
<value>处理 bean 1</value>
<value>处理 bean 2</value>
</list>
</property>
</bean>
<2.2> 更牛的自动代理DefaultAdvisorAutoProxyCreator,
特点:多种接口或者多个类 自动创建其对应代理,不需要指定接口或者类,提供Advisor(切入点+通知),默认搜索所有的Advisor 如前面的正则表达式
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
(1).before advice(前置通知) implements MethodBeforeAdvice 重写before()方法
是在目标bean方法调用前调用,没有返回值,通常意外情况下,会继续运行下一步方法.记住的一点是没有返回
例子如下
public class MyBeforeAdvisor implements MethodBeforeAdvice
{
public void before(Method m, Object[] args, Object target) throws Throwable
{
System.out.println("方法调用之前...");
System.out.println("下面是方法调用的信息:");
System.out.println("所执行的方法是:" + m);
System.out.println("调用方法的参数是:" + args);
System.out.println("目标对象是:" + target);
System.out.println("方法调用之前111...");
}
}
(2).after advice(后置通知) implements AfterReturningAdvice 重写afterReturning()方法
是在方法调用后调用,有返回值,记住的一点是有返回值。
public void afterReturning(Object returnValue, Method m, Object[] args, Object target)throws Throwable
{
System.out.println("方法调用结束...");
System.out.println("目标方法的返回值是 : " + returnValue);
System.out.println("目标方法是 : " + m);
System.out.println("目标方法的参数是 : " + args);
System.out.println("目标对象是 : " + target);
}
(3).around advice(环绕通知) implements MethodInterceptor 重写其内的invoke()方法,实现方式与Struts2的拦截器一模一样
调用其 MethodInvocation 的proceed()方法;
例子如下
public class MyAroundInterceptor implements MethodInterceptor
{
public Object invoke(MethodInvocation invocation) throws Throwable
{
System.out.println("调用生小孩方法之前娶老婆: invocation对象:[" + invocation + "]");
Object rval = invocation.proceed();
System.out.println("调用方法之后...坐月子");
return rval;
}
}
(4).throws advice(异常通知) implements ThrowsAdvice
例子如下
public class MyExceptionAdvice implements ThrowsAdvice
{
public void afterThrowing(ClassNotFoundException ex) throws Throwable
{
System.out.println("系统抛出ClassNotFoundException异常,异常提示为: " + ex.getMessage());
}
public void afterThrowing(Method m,Object[] o,Object target,Throwable e)throws Throwable{
System.out.println("消息:"+e.getMessage());
}
public void afterThrowing(Method m, Object[] args, Object target, ArithmeticException ex)
{
System.out.println("系统抛出ArithmeticException异常,异常提示为: " + ex.getMessage());
System.out.println("抛出异常的方法为: " + m);
System.out.println("抛出异常的方法的参数为: " + args);
System.out.println("抛出异常的目标对象为: " + target);
}
}
(5).introduce advice(引入通知)
引入通知是一种特殊的通知,它能将新的成员变量、成员方法引入到目标类中。它不能作用于任何切入点,
因为它只作用于类层次,而不是方法层次。实现引入通知需要实现IntroductionAdvisor和IntroductionInterceptor接口。
引入通知不能调用proceed方法。Advisor必须针对每个实例,并且是有状态的。
引入通知的效果类似于设计模式中的访问者模式(Visitor Pattern)
3.AOP实现过程中的几种不同的方式:
3.1:拦截一类中所有的方法(连接点)
3.2:拦截一个类中的某些符合条件的方法(切入点)
3.3:拦截多个类中的符合条件的方法(切面)
4 利用aop进行事务编程 Spring事务配置的五种方式 (掌握Spring事务体系图)
传统上,J2EE开发者有两个事务管理的选择: 全局 或 本地事务(局部事务)。全局事务由应用服务器管理,使用JTA。
局部事务是和资源相关的,比如一个和JDBC连接关联的事务
事务种类分为: jdbc事务(局部事务) jta事务(全局事务) 容器事务
1、JDBC事务控制的局限性在一个数据库连接内,但是其使用简单。局部事务
2、JTA事务的功能强大,事务可以跨越多个数据库或多个DAO,使用也比较复杂。全局事务
3、容器事务,主要指的是J2EE应用服务器提供的事务管理,局限于EJB应用
两种事务的比较
1、JDBC事务控制的局限性在一个数据库连接内,但是其使用简单。
2、JTA事务的功能强大,事务可以跨越多个数据库或多个DAO,使用也比较复杂
从实现的角度划分
Spring把事务分为两种一种是:编程式事务,一种是声明式事务。
编程式事务是侵入式事务 比较灵活,编程式事务则要操作逻辑代码。存在重复的代码比较多,相对繁琐,而且不利于系统的扩展;
声明式事务是非侵入式的事务。声明式事务只需在配置文件中配置,而不需要去操作逻辑代码。
spring事务的7大传播属性
1.PROPAGATION_MANDATORY:要求调用该方法的线程必须处于事务环境中,否则抛出异常。
2.PROPAGATION_NESTED:如果执行该方法的线程已处于事务环境下,依然启动新的事务,方法在嵌套的事务里执行。
如果执行该方法的线程并未处于事务中,也启动新的事务,然后执行该方法,此时与PROPAGATION_REQUIRED相同。
3.PROPAGATION_NEVER:不允许调用该方法的线程处于事务环境下,如果调用该方法的线程处于事务环境下,则抛出异常。
4.PEOPAGATION_NOT_SUPPORTED:如果调用该方法的线程处于在事务中,则先暂停当前事务,然后执行该方法。
5.PEOPAGATION_REQUIRED:要求在事务环境中执行该方法,如果当前执行线程已处于事务中,则直接调用,
如果当前执行线程不已处于事务中,则启动新的事务后执行该方法。
6.PEOPAGATION_REQUIRES_NEW:该方法要求有一个在新的事务环境中执行,如果当前执行线程已处于事务中,
先暂停当前事务,启动新的事务后执行该方法;如果当前执行线程不已处于事务中,则启动新的事务后执行该方法。
7.PEOPAGATION_SUPPORTS:如果当前执行线程已处于事务中,则使用当前事务,否则不使用事务。
Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部 DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。根据代理机制的不同,总结了五种Spring事务的配置方式
现在以dataSource为例,当然要先配置dataSource,参见去前面文档spring方式获得dataSource部分
<1> 每个bean有一个代理
<1.1>配置事务管理器transactionManager
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 给DataSourceTransactionManager注入dataSource-->
<property name="dataSource"><ref local="dataSource"/></property>
</bean>
<1.2>配置事务代理bean TransactionProxyFactoryBean
<bean id="xxx"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 配置事务管理器 引用上面配置的来注入 -->
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="操作数据库的目标 dao bean id" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<2> 所有Bean共享一个代理基类 实则上就是spring 的模板机制 配置一个模板,使其为abstract="true"
spring中bean 的继承 在java 类中称为继承 在spring称为模板
<2.1>代理定义 定义模板(父类)
<bean id="baseTxProxy" lazy-init="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<2.2> 为不同的dao操作类加上事务
<!-- 给dao1加事务-->
<bean id="daotran1" parent="baseTxProxy"> <!-- baseTxProxy为刚刚配置的模板-->
<property name="target">
<ref local="dao1"/>
</property>
</bean>
<!-- 给dao2加事务-->
<bean id="daotran2" parent="baseTxProxy">
<property name="target">
<ref local="dao2"/>
</property>
</bean>
<3>使用拦截器
<3.1>定义事务拦截器 org.springframework.transaction.interceptor.TransactionInterceptor
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 配置事务管理器 引用上面配置的来注入 -->
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<3.2> 定义代理 bean 采用自动代理 BeanNameAutoProxyCreator (前面讲过有例子)
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*dao</value> <!-- dao bean id匹配 -->
</list>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value> <!-- 引用事务拦截器 -->
</list>
</property>
</bean>
13 spring与struts的整合
整合中要思考的是:怎样才能加载和实例化spring容器.先把spring容器放到web容器中,然后再根据一些方法去提取,
13.1 在Strust1中直接使用spring
让我们回顾一下前面所讲的如何在web环境中使用spring,
根据servlet版本的不用,我们可以通过在web.xml里配置servlet或者监听器来实例化spring容器,
1.在web.xml中配置
①.加载spring 容器
<!-- 加载spring 容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/beans.xml</param-value>
</context-param>
②.实例化spring 容器
<!-- 初始化spring容器方法一 servlet版本 前面有讲述-->
<servlet>
<servlet-name>contextLoader</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<!-- 初始化spring容器方法二 监听器版 前面有讲述-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
之后就可以通过WebApplicationContextUtils取得Spring的上下文
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(当前ServletContext);
如在struts1中,必须知道当前的servlet上下文
①WebApplicationContext ctx=WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
②WebApplicationContext beanFactory=WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());
如在struts2中
WebApplicationContext ctx=WebApplicationContextUtils.getWebApplicationContext(ServletActionContext.getServletContext());
有了WebApplicationContext实例,我们就可以通过getBean方法获得spring容器中的bean了,如下所示
13.2 Strust1整合Spring的其他3种方式
在上面的Strust1中直接使用Spring,我们是通过在web.xml中配置servlet或者是listener加载和实例化spring容器。实则上
spring提供了一种专门针对于struts的插件来加载和实例化spring容器,只需在struts-config.xml加入即可,
所以我们如果不想用前面的来加载可以使用下面的
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="/WEB-INF/classes/applicationContext.xml" />
</plug-in>
<!--
注意 /WEB-INF/classes/applicationContext.xml这个位置,如果你的文件在WEB-INF。则写成/WEB-INF/applicationContext.xml
在eclipse 中 /WEB-INF/classes/applicationContext.xml对应的目录是src目录,applicationContext.xml放在src下
-->
◆使用Spring的ActionSupport类整合Structs
优点:
1) 简单
缺点:
1) 耦合高 它将Struts动作与Spring框架耦合在一起。如果您想替换掉Spring,那么您必须重写代码
2) 违反IOC
3) 无法使用 DispatchAction
◆使用Spring的DelegatingRequestProcessor覆盖Struts的RequestProcessor
DelegatingRequestProcessor方法的确比第一种方法好,缺点 RequestProcessor如果改变了怎么办或者是有不同的RequestProcessor怎么办呢
◆将Struts Action管理委托给Spring框架
动作委托解决方法是这三种方法中最好的。Struts动作不了解Spring,不对代码作任何改变就可用于非Spring应用程序中。RequestProcessor的改变不会影响它,并且它可以利用Spring AOP特性的优点。
优点
1. 动作委托解决方法是这三种方法中最好的。
2. 不使用Spring api编写 Action
3. 利用了IOC装配
三种方式的相关配置:
<1> Action直接继承ActionSupport,在Action类的execute()方法中通过
ApplicationContext ctx=getWebApplicationContext()获得Spring的
上下文,通过上下文获取相应的bean实例
<2>覆盖RequestProcessor
1.在struts-config.xml中配置控制器
<controller processorClass="org.springframework.web.struts.DelegatingRequestProcessor"/>
2.在applicationContext.xml文件中注册action动作bean
<bean name="/struts-config.xml配置的对应action的path" class="Action类的包名类名" >
<!--注意上面的是name而不是大家经常写的id-->
<property name="service">
<ref bean="service" /> <!--注入spring实例,假设属性名为service-->
</property>
</bean>
3.Action类中声明一个Service私有属性及其setter方法,通过IOC注入Service实例。
<3>动作管理委托给Spring
1.struts-config.xml中action标签内的type属性值替换为org.springframework.web.struts.DelegatingActionProxy,如下
<action input="/index.jsp" path="/hello" scope="session"
type="org.springframework.web.struts.DelegatingActionProxy">
<forward name="success" path="/success.jsp" />
</action>
2.在applicationContext.xml文件中注册action动作bean
<bean name="/struts-config.xml配置的对应action的path" class="Action类的包名.类名" >
<property name="service">
<ref bean="service" />
</property>
</bean>
3.Action类中声明一个Service私有属性及其setter方法,通过IOC注入Service实例
13.2 Spring与Struts2的整合
由于Struts2得强大可插拔式设计,使得整合spring的工作变得异常简单,struts2-spring-plugin-2.0.8.jar就是支持spring的插件包
0.把struts2支持spring的插件包jar拷贝到项目中
1.web.xml的配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- 监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 定义Struts2的FilterDispathcer的Filter -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<!-- FilterDispatcher用来初始化struts2并且处理所有的WEB请求。 -->
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
2.applicationContext.xml的配置(WEB-INF目录下)
(如果不使用默认的 则可以在web.xml通过以下配置修改xml的配置以及名称)
<!-- 加载spring 容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/beans.xml</param-value>
</context-param>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-2.5.xsd">
<bean name="service" class="com.service.impl.ServiceImpl"/>
<!-- action的配置 -->
<bean name="abc" class="com.LoginAction" >
<property name="service">
<ref bean="service" /> <!--注入spring实例,假设action类中有一个属性名为service-->
</property>
</bean>
</beans>
3.struts.xml的配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<include file="struts-default.xml" />
<package name="default" extends="struts-default">
<!-- action标签中的class属性与applicationContext.xml中的action的bean的name属性一致 如以下的abc -->
<action name="login" class="abc">
<result name="input" >/login.jsp</result>
<result name="success">/welcome.jsp</result>
<result name="error">/failed.jsp</result>
</action>
</package>
</struts>
4.action类中声明service的一个变量及setter方法
14 Spring2.5有哪些改进
Spring2.5rc1发布了,一直想知道它葫芦里卖什么药
1 spring bean的作用域 已经有原来的单例和非单例 变成了5个
2 Jar 包:一个包分解成多个包 如 SpringMVC 不再使用spring.jar 这个庞大的包了。 Spring-webmvc.jar, spring-webmvc-portlet.jar 可以在 lib/modules 目录下找到,而且对于Struts1.* 的支持的包也应该改成 spring-webmvc-struts.jar了。
3 Hibernate:注意Spring已经不再支持Hibernate 3.1之前的版本了,也就是说2.1,3.0的版本也无法使用了。如果仍然要用的话,推荐使用Spring的2.0.6/2.0.7版本。
4. JDK版本: JDK至少要1.4.2以上,如果仍然打算使用1.3的话就请用2.0.6/2.0.7版本吧。
5. XML配置:推荐使用XML metadata格式,不过先前的DTD仍然支持。需要注意的一点是,Spring2.0的DTD继续使用“singleton”属性,但是新的Spring2.5 DTD不允许使用“singleton”属性了,改成“scope”属性来描述bean的生命周期。
6. 废弃的类与方法:有些在先前版本标注过“@deprecated”的类与方法已经完全被废弃了。
比如:
1.
ResultReader : 被 RowMapper 接口取代。
2.
BeanFactoryBootstrap : 考虑使用 BeanFactoryLocator 或自定义的bootstrap类来代替。
7. Apache OJB:注意Spring源代码中已经完全把这个去掉了,但与之整合的类仍然可以在Spring Modules project找到。https://springmodules.dev.java.net/
8. iBATIS:注意Spring已经不再支持iBATIS 的1.3版本了, 如果想继续的话,请升级到2.3以上吧。
9. JDO:注意Spring已经不支持JDO1.0了。同样,你可以升级到2.0以上版本,或者使用Spring的2.0.6/2.0.7版本。
10. UrlFilenameViewController:这个东东我也没有接触过,这里,我就简单翻译一下吧。
“考虑到嵌套路径的请求,视图名称现在决定叫UrlFilenameViewController了,这是一个突破性的改变,并且意味着如果你从Spring1.* 升级到Spring2.0 你可以使用该类从而减少Spring Web MVC的配置工作。”
15 spring 注解
<一> 1 @Autowired 2 @Autowired
@Qualifier("bean名称")
需要<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<二> JSR-250 的注释 @Resource @PostConstruct 和 @PreDestroy
加入common-annotations.jar包
需要<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
可用 <context:annotation-config/>。简化第一和第二的配置 请看下面的配置:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config/>
<bean id="chinese" class="com.Chinese"></bean>
<bean id="American" class="com.American"></bean>
<bean id="test" class="com.Test"></bean>
</beans>
<三> @Component
Component或者@Component("bean名") @Component默认bean名为类名 首字母小写
不需要配置bean 配置文件如下
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="com"/> <!--com包 这里改成你的包名-->
</beans>
以下是具体说明 高手可掠过
Spring 通过一个 BeanPostProcessor 对 注解进行解析,所以要让 注解 起作用必须事先在 Spring 容器中声明 AutowiredAnnotationBeanPostProcessor Bean。
如下
<!-- 该 BeanPostProcessor 将自动起作用,对标注 @Autowired 的 Bean 进行自动注入 -->
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
15.1 Spring 2.5 引入了 @Autowired 注解,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作,按照类型进行装配
如
@Autowired
public void setP(Person p) {
this.p = p;
}
15.2 当不存在不匹配的bean或者是匹配的bean的数目大于1时,按照类型进行装配都会报出异常,可采用以下方式不报都会报出异常
@Autowired(required = false)
15.3 采用以下方式指定bean,按名字匹配
@Autowired
@Qualifier("bean名称")
用在构造方法上
@Autowired
public Test(@Qualifier("chinese")Person p) {
// TODO Auto-generated constructor stub
this.p=p;
}
15.3 使用 JSR-250 的注释 @Resource @PostConstruct 和 @PreDestroy
Spring 不但支持自己定义的 @Autowired 的注释,还支持几个由 JSR-250 规范定义的注释,它们分别是 @Resource、@PostConstruct 以及 @PreDestroy。
为了让 JSR-250 的注释生效,除了在 Bean 类中标注这些注释外,还需要在 Spring 容器中注册一个负责处理这些注释的 BeanPostProcessor:
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
@Resource
@Resource 的作用相当于 @Autowired,只不过 @Autowired 按 byType 自动注入,面 @Resource 默认按 byName 自动注入罢了。@Resource 有两个属性是比较重要的,分别是 name 和 type,Spring 将 @Resource 注释的 name 属性解析为 Bean 的名字,而 type 属性则解析为 Bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。
Resource 注释类位于 Spring 发布包的 lib/j2ee/common-annotations.jar 类包中,因此在使用之前必须将其加入到项目的类库中。
JSR-250 为初始化之后/销毁之前方法的指定定义了两个注释类,分别是 @PostConstruct 和 @PreDestroy,这两个注释只能应用于方法上。标注了 @PostConstruct 注释的方法将在类实例化后调用,而标注了 @PreDestroy 的方法将在类销毁之前调用。
使用 <context:annotation-config/> 简化配置
而我们前面所介绍的 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 就是处理这些注释元数据的处理器。但是直接在 Spring 配置文件中定义这些 Bean 显得比较笨拙。Spring 为我们提供了一种方便的注册这些 BeanPostProcessor 的方式,这就是
<context:annotation-config/>。请看下面的配置:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config/>
<bean id="chinese" class="com.Chinese"></bean>
<bean id="American" class="com.American"></bean>
<bean id="test" class="com.Test"></bean>
</beans>
<context:annotationconfig/> 将隐式地向 Spring 容器注册 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor 以及 equiredAnnotationBeanPostProcessor 这 4 个 BeanPostProcessor。
15.4 使用 @Component或者@Component("bean名") @Component默认bean名为类名 首字母小写
然我们可以通过 @Autowired 或 @Resource 在 Bean 类中使用自动注入功能,但是 Bean 还是在 XML 文件中通过 <bean> 进行定义 —— 也就是说,在 XML 配置文件中定义 Bean,通过 @Autowired 或 @Resource 为 Bean 的成员变量、方法入参或构造函数入参提供自动注入的功能。能否也通过注释定义 Bean,从 XML 配置文件中完全移除 Bean 定义的配置呢?答案是肯定的,我们通过 Spring 2.5 提供的 @Component 注释就可以达到这个目标了。
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="com"/><!--com包-->
</beans>
相关推荐
Spring、SpringMVC和Mybatis是Java开发中最常用的三大开源框架,它们的整合使用,通常被称为SSM框架。这个框架组合提供了完整的后端服务解决方案,包括依赖注入(DI)、面向切面编程(AOP)、模型-视图-控制器(MVC...
弃用了struts,用spring mvc框架做了几个项目,感觉都不错,而且使用了注解方式,可以省掉一大堆配置文件。本文主要介绍使用注解方式配置的spring mvc,之前写的spring3.0 mvc和rest小例子没有介绍到数据层的内容,...
java *spring工具类 方便在非spring管理环境中获取beanjava *spring工具类 方便在非spring管理环境中获取beanjava *spring工具类 方便在非spring管理环境中获取beanjava *spring工具类 方便在非spring管理环境中获取...
Spring Integration + Spring WS 整合 在 Java 领域中,Spring Integration 和 Spring WS 是两个常用的框架,它们分别负责集成系统和 Web 服务。今天,我们将探讨如何将这两个框架整合在一起,实现一个完整的 Web ...
包含spring 3.0.5的所有jar文件: org.springframework.aop-3.0.5.RELEASE.jar org.springframework.asm-3.0.5.RELEASE.jar org.springframework.aspects-3.0.5.RELEASE.jar org.springframework.beans-3.0.5.RELEASE...
Spring Batch是一个轻量级的,完全面向Spring的批处理框架,可以应用于企业级大量的数据处理系统。Spring Batch以POJO和大家熟知的Spring框架为基础,使开发者更容易的访问和利用企业级服务。Spring Batch可以提供...
Spring框架是Java应用程序开发中的一个核心组件,它提供了一个丰富的IOC(Inversion of Control,控制反转)和AOP(Aspect-Oriented Programming,面向切面编程)功能,使得开发者能够更方便地管理对象和实现模块化...
在Java开发领域,Spring Boot和Spring Batch的整合是构建高效批处理系统的一种常见方式。Spring Boot以其简洁的配置和快速的启动能力深受开发者喜爱,而Spring Batch作为Spring框架的一部分,专注于批量处理任务,...
在构建分布式系统时,Spring Cloud Gateway 作为微服务架构中的边缘服务或 API 网关,扮演着至关重要的角色。它负责路由请求到相应的微服务,并可以提供过滤器功能,如限流、熔断等。而Spring Security 则是 Java ...
spring3.1官方所有的jar包 org.springframework.aop-3.1.RELEASE.jar org.springframework.asm-3.1.RELEASE.jar org.springframework.aspects-3.1.RELEASE.jar org.springframework.beans-3.1.RELEASE.jar org....
这篇文章将教你快速地上手使用 Spring 框架. 如果你手上有一本《Spring in Action》, 那么你最好从第三部分"Spring 在 Web 层的应用--建立 Web 层"开始看, 否则那将是一场恶梦! 首先, 我需要在你心里建立起 Spring...
spring-framework-3.2.18.RELEASE-Gradle编译无误-可直接导入eclipse查看。已使用Gradle编译成eclipse项目的spring源码,版本是3.2.18。可以直接导入eclipse中,导入法方法可参看:...
Getting started with Spring Framework (4th Edition) is a hands-on guide to begin developing applications using Spring Framework 5. The examples (consisting of 88 sample projects) that accompany this ...
Spring 详细讲解 Spring 是一个功能强大且功能齐全的 Java 应用程序框架,提供了一个通用的基础结构来支持开发企业级应用程序。 Spring 框架的核心是控制反转(IoC)和依赖注入(DI)模式,它们使得应用程序更加...
Spring Cloud系列教程 Spring Boot Spring Cloud Stream 和 Kafka案例教程 springcloud生产者与消费者项目实战案例 Spring Cloud 中断路器 Circuit Breaker的应用 配置 Spring Cloud Config Server Spring Cloud ...
介绍一个基于Spring Boot 3.0、Spring Cloud 2022 & Alibaba的微服务RBAC权限管理系统。该系统可以实现微服务RBAC权限管理,通过RBAC权限管理机制对用户访问系统的权限进行限制,从而提高系统的安全性和可用性。同时...
项目原型:Struts2.3.16 + Spring4.1.1 + Hibernate4.3.6 二、 项目目的: 整合使用最新版本的三大框架(即Struts2、Spring4和Hibernate4),搭建项目架构原型。 项目架构原型:Struts2.3.16 + Spring4.1.1 + ...
Spring Cloud和Spring Boot是两个非常重要的Java开发框架,它们在微服务架构中扮演着核心角色。Spring Boot简化了创建独立的、生产级别的基于Spring的应用程序的过程,而Spring Cloud则为开发者提供了快速构建分布式...
《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》从源代码的角度对Spring的内核和各个主要功能模块的架构、设计和实现原理进行了深入剖析。你不仅能从本书中参透Spring框架的出色架构和设计思想,还能从...
《Spring AI Core 0.8.1:开启人工智能之旅》 在现代软件开发领域,Spring框架以其强大的功能和灵活性,已经成为Java开发中的首选框架之一。而Spring AI Core则是Spring生态系统中专门为人工智能(AI)和机器学习...