- 浏览: 22945 次
- 性别:
- 来自: 广州
文章分类
最新评论
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小例子没有介绍到数据层的内容,...
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...
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 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 AI Core 0.8.1:开启人工智能之旅》 在现代软件开发领域,Spring框架以其强大的功能和灵活性,已经成为Java开发中的首选框架之一。而Spring AI Core则是Spring生态系统中专门为人工智能(AI)和机器学习...
《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》从源代码的角度对Spring的内核和各个主要功能模块的架构、设计和实现原理进行了深入剖析。你不仅能从本书中参透Spring框架的出色架构和设计思想,还能从...
Spring 框架是 Java 开发中的一个核心组件,它为构建企业级应用程序提供了全面的编程和配置模型。Spring 4.3.14 是该框架的最后一个4.x系列正式版,发布于2018年2月24日。这个版本在Spring 5.0发布之前提供了一个...
在IT行业中,Spring框架是Java应用开发中的一个关键组件,它提供了一整套服务来简化企业级应用的构建。RabbitMQ则是一个流行的开源消息队列系统,它基于AMQP(Advanced Message Queuing Protocol)协议,用于高效地...
Spring Cloud系列教程 Spring Boot Spring Cloud Stream 和 Kafka案例教程 springcloud生产者与消费者项目实战案例 Spring Cloud 中断路器 Circuit Breaker的应用 配置 Spring Cloud Config Server Spring Cloud ...
Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。Spring MVC4是当前zuixin的版本,在众多特性上有了进一步的提升。, 在精通Spring...