<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Java豆技术站点 &#187; Spring</title>
	<atom:link href="http://javadou.com/framework/spring-framework/feed/" rel="self" type="application/rss+xml" />
	<link>http://javadou.com</link>
	<description>Java</description>
	<lastBuildDate>Wed, 21 Jul 2010 08:08:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>连接池泄露的问题：Timeout waiting for idle object</title>
		<link>http://javadou.com/org-apache-commons-dbcp-sqlnestedexception-cannot-get-a-connection-pool-exhausted-causejava-util-nosuchelementexcep-638/</link>
		<comments>http://javadou.com/org-apache-commons-dbcp-sqlnestedexception-cannot-get-a-connection-pool-exhausted-causejava-util-nosuchelementexcep-638/#comments</comments>
		<pubDate>Tue, 13 Jul 2010 10:58:47 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Java核心类]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Timeout waiting for idle object]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=638</guid>
		<description><![CDATA[问题描述:连接池泄露的问题：org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool exhausted, cause:java.util.NoSuchElementException: Timeout waiting for idle object 问题同样适用于其他服务器,使用spring配置文件的可以加下面的参... ]]></description>
			<content:encoded><![CDATA[<p>问题描述:<strong>连接池泄露的问题：org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool exhausted, cause:java.util.NoSuchElementException: Timeout waiting for idle object</strong><br />
问题同样适用于其他服务器,使用spring配置文件的可以加下面的参数<br />
&lt;property name=&#8221;removeAbandoned&#8221; value=&#8221;true&#8221;/&gt;<br />
&lt;property name=&#8221;removeAbandonedTimeout&#8221; value=&#8221;60&#8243;/&gt;<br />
&lt;property name=&#8221;logAbandoned&#8221; value=&#8221;true&#8221;/&gt;</p>
<p>1 问题描述<br />
Web程序在tomcat刚开始运行时速度很快，但过一段时间后发现速度变得很慢。<br />
检查日志输出，发现异常如下:<br />
org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool exhausted, cause:<br />
java.util.NoSuchElementException: Timeout waiting for idle object<br />
同时在SQLServer事件探查器中发现，每执行一次sql语句都要产生Audit login事件，语句执行后产生<br />
Audit logout事件。说明每一次tomcat都是重新打开新的连接。<br />
2 问题解决<br />
tomcat 的数据源定义提供了三个参数：<br />
a. 如果设为true则tomcat自动检查恢复重新利用，没有正常关闭的Connection.（默认是false）<br />
&lt;parameter&gt;<br />
&lt;name&gt;removeAbandoned&lt;/name&gt;<br />
&lt;value&gt;true&lt;/value&gt;<br />
&lt;/parameter&gt;<br />
b. 设定连接在多少秒内被认为是放弃的连接，即可进行恢复利用。<br />
&lt;parameter&gt;<br />
&lt;name&gt;removeAbandonedTimeout&lt;/name&gt;<br />
&lt;value&gt;60&lt;/value&gt;<br />
&lt;/parameter&gt;<br />
c. 输出回收的日志，可以详细打印出异常从而发现是在那里发生了泄漏<br />
&lt;parameter&gt;<br />
&lt;name&gt;logAbandoned&lt;/name&gt;<br />
&lt;value&gt;true&lt;/value&gt;<br />
&lt;/parameter&gt;</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/org-apache-commons-dbcp-sqlnestedexception-cannot-get-a-connection-pool-exhausted-causejava-util-nosuchelementexcep-638/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SpringMVC数据绑定xx.yy.zz 时的yy对象初始化</title>
		<link>http://javadou.com/springmvc-xx-yy-zz-init-java-599/</link>
		<comments>http://javadou.com/springmvc-xx-yy-zz-init-java-599/#comments</comments>
		<pubDate>Thu, 29 Apr 2010 22:09:32 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=599</guid>
		<description><![CDATA[SpringMVC数据绑定xx.yy.zz 时的yy对象初始化 Spring Mvc 中的SimpleFormController是专门负责数据绑定的Controller ，当做深层绑定时，xx.yy.zz  如果yy 对象为null 就会抛出空指针.我在前期用如下代码进行初始化 Article article = ... ]]></description>
			<content:encoded><![CDATA[<p>SpringMVC数据绑定xx.yy.zz 时的yy对象初始化<br />
<span>Spring Mvc 中的SimpleFormController是专门负责数据绑定的Controller ，当做深层绑定时，xx.yy.zz  如果yy 对象为null<br />
就会抛出空指针.我在前期用如下代码进行初始化<br />
Article article = new Article();<br />
MainType articleType = new MainType();<br />
article.setMainType(articleType);<br />
显尔易见这段代码繁琐的，经过摸索，利用java 反射机制，编写了一个公共方法进行初始化<br />
package com.allcom.base.commons;</p>
<p>import java.lang.reflect.Field;<br />
import java.lang.reflect.Method;</p>
<p>import com.allcom.vvgoo.persist.Merchant;<br />
/** *//** *//** *//**<br />
* 初始化对像的属性 ,对于日期型数据将自动填充当前日期<br />
*<br />
* */<br />
public class AutoView {</p>
<p>public static void AutoView(Object command){<br />
if(null!=command){<br />
Class classType = command.getClass();<br />
Field fields[]  = classType.getDeclaredFields();<br />
for(int i=0;i&lt;fields.length;i++){<br />
Field field = fields[i];<br />
String fieldName = field.getName();<br />
String typeName =field.getType().getName();<br />
String firstLetter = fieldName.substring(0,1).toUpperCase();</p>
<p>String getMethodName = &#8221;get&#8221;+firstLetter+fieldName.substring(1);<br />
String setMethodName = &#8221;set&#8221;+firstLetter+fieldName.substring(1);</p>
<p>try {<br />
Method setMethod = classType.getMethod(setMethodName,new Class[]{field.getType()});<br />
Class clazz = Class.forName(typeName);<br />
Object value = clazz.newInstance();<br />
if (null!=value){<br />
setMethod.invoke(command,new Object[]{value});<br />
}<br />
} catch (Exception e) {</p>
<p>}</p>
<p>}<br />
}<br />
}</p>
<p>public static void main(String[] arg){<br />
Merchant merchant = new Merchant();<br />
AutoView view = new AutoView();<br />
view.AutoView(merchant);<br />
System.out.print(Util.dateToString(merchant.getCreateDate(), &#8221;yyyy-MM-dd&#8221;));</p>
<p>}</p>
<p>}</p>
<p>其中 Merchant 是任意的一个javaBean，在使用该方法处理后，其中xx.yy.zz 中的yy 对象会自动填充该对象全新的实例</span></p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/springmvc-xx-yy-zz-init-java-599/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>spring annotation注解 详细介绍</title>
		<link>http://javadou.com/spring-annotation-630/</link>
		<comments>http://javadou.com/spring-annotation-630/#comments</comments>
		<pubDate>Mon, 19 Apr 2010 00:50:05 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[注解]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=630</guid>
		<description><![CDATA[1. 使用Spring注解来注入属性 1.1. 使用注解以前我们是怎样注入属性的 类的实现： Java代码 public class UserManagerImpl implements UserManager { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } &8230; } public cl... ]]></description>
			<content:encoded><![CDATA[<p>1. 使用Spring注解来注入属性<br />
1.1. 使用注解以前我们是怎样注入属性的<br />
类的实现：</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li>public class UserManagerImpl implements UserManager {</li>
<li> private UserDao userDao;</li>
<li> public void setUserDao(UserDao userDao) {</li>
<li> this.userDao = userDao;</li>
<li> }</li>
<li> &#8230;</li>
<li>}</li>
</ol>
</div>
<pre>public class UserManagerImpl implements UserManager {
 private UserDao userDao;
 public void setUserDao(UserDao userDao) {
  this.userDao = userDao;
 }
 ...
}</pre>
<p>配置文件：</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li>&lt;bean id=&#8221;userManagerImpl&#8221; class=&#8221;com.kedacom.spring.annotation.service.UserManagerImpl&#8221;&gt;</li>
<li> &lt;property name=&#8221;userDao&#8221; ref=&#8221;userDao&#8221; /&gt;</li>
<li>&lt;/bean&gt;</li>
<li>&lt;bean id=&#8221;userDao&#8221; class=&#8221;com.kedacom.spring.annotation.persistence.UserDaoImpl&#8221;&gt;</li>
<li> &lt;property name=&#8221;sessionFactory&#8221; ref=&#8221;mySessionFactory&#8221; /&gt;</li>
<li> &lt;/bean&gt;</li>
</ol>
</div>
<pre>&lt;bean id="userManagerImpl"&gt;
 &lt;property name="userDao" ref="userDao" /&gt;
&lt;/bean&gt;
&lt;bean id="userDao"&gt;
 &lt;property name="sessionFactory" ref="mySessionFactory" /&gt;
&lt;/bean&gt;</pre>
<p>1.2. 引入@Autowired注解（不推荐使用，建议使用@Resource）<br />
类的实现（对成员变量进行标注）</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li>public class UserManagerImpl implements UserManager {</li>
<li> <span style="color: #646464;">@Autowired</span></li>
<li> private UserDao userDao;</li>
<li> &#8230;</li>
<li>}</li>
</ol>
</div>
<pre>public class UserManagerImpl implements UserManager {
 @Autowired
 private UserDao userDao;
 ...
}</pre>
<p>或者（对方法进行标注）</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li>public class UserManagerImpl implements UserManager {</li>
<li> private UserDao userDao;</li>
<li> <span style="color: #646464;">@Autowired</span></li>
<li> public void setUserDao(UserDao userDao) {</li>
<li> this.userDao = userDao;</li>
<li> }</li>
<li> &#8230;</li>
<li>}</li>
</ol>
</div>
<pre>public class UserManagerImpl implements UserManager {
 private UserDao userDao;
 @Autowired
 public void setUserDao(UserDao userDao) {
  this.userDao = userDao;
 }
 ...
}</pre>
<p>配置文件</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li>&lt;bean id=&#8221;userManagerImpl&#8221; class=&#8221;com.kedacom.spring.annotation.service.UserManagerImpl&#8221; /&gt;</li>
<li>&lt;bean id=&#8221;userDao&#8221; class=&#8221;com.kedacom.spring.annotation.persistence.UserDaoImpl&#8221;&gt;</li>
<li> &lt;property name=&#8221;sessionFactory&#8221; ref=&#8221;mySessionFactory&#8221; /&gt;</li>
<li> &lt;/bean&gt;</li>
</ol>
</div>
<pre>&lt;bean id="userManagerImpl" /&gt;
&lt;bean id="userDao"&gt;
 &lt;property name="sessionFactory" ref="mySessionFactory" /&gt;
&lt;/bean&gt;</pre>
<p>@Autowired可以对成员变量、方法和构造函数进行标注，来完成自动装配的工作。以上两种不同实现方式中，@Autowired的标注位置不同，它 们都会在Spring在初始化userManagerImpl这个bean时，自动装配userDao这个属性，区别是：第一种实现中，Spring会直 接将UserDao类型的唯一一个bean赋值给userDao这个成员变量；第二种实现中，Spring会调用setUserDao方法来将 UserDao类型的唯一一个bean装配到userDao这个属性。</p>
<p>1.3. 让@Autowired工作起来<br />
要使@Autowired能够工作，还需要在配置文件中加入以下代码</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li>&lt;bean class=&#8221;org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor&#8221; /&gt;</li>
</ol>
</div>
<pre>&lt;bean /&gt;</pre>
<p>1.4. @Qualifier<br />
@Autowired是根据类型进行自动装配的。在上面的例子中，如果当Spring上下文中存在不止一个UserDao类型的bean时，就会抛出 BeanCreationException异常；如果Spring上下文中不存在UserDao类型的bean，也会抛出 BeanCreationException异常。我们可以使用@Qualifier配合@Autowired来解决这些问题。<br />
1. 可能存在多个UserDao实例</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li><span style="color: #646464;">@Autowired</span></li>
<li>public void setUserDao(<span style="color: #646464;">@Qualifier</span>(&#8220;userDao&#8221;) UserDao userDao) {</li>
<li> this.userDao = userDao;</li>
<li>}</li>
</ol>
</div>
<pre>@Autowired
 public void setUserDao(@Qualifier("userDao") UserDao userDao) {
  this.userDao = userDao;
 }</pre>
<p>这样，Spring会找到id为userDao的bean进行装配。<br />
2. 可能不存在UserDao实例</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li><span style="color: #646464;">@Autowired</span>(required = false)</li>
<li>public void setUserDao(UserDao userDao) {</li>
<li> this.userDao = userDao;</li>
<li>}</li>
</ol>
</div>
<pre>@Autowired(required = false)
 public void setUserDao(UserDao userDao) {
  this.userDao = userDao;
 }</pre>
<p>1.5. @Resource（JSR-250标准注解，推荐使用它来代替Spring专有的@Autowired注解）<br />
Spring 不但支持自己定义的@Autowired注解，还支持几个由JSR-250规范定义的注解，它们分别是@Resource、@PostConstruct以及@PreDestroy。<br />
@Resource的作用相当于@Autowired，只不过@Autowired按byType自动注入，而@Resource默认按byName自动 注入罢了。@Resource有两个属性是比较重要的，分别是name和type，Spring将@Resource注解的name属性解析为bean的 名字，而type属性则解析为bean的类型。所以如果使用name属性，则使用byName的自动注入策略，而使用type属性时则使用byType自 动注入策略。如果既不指定name也不指定type属性，这时将通过反射机制使用byName自动注入策略。<br />
@Resource装配顺序</p>
<ol>
<li>如果同时指定了name和type，则从Spring上下文中找到唯一匹配的bean进行装配，找不到则抛出异常</li>
<li>如果指定了name，则从上下文中查找名称（id）匹配的bean进行装配，找不到则抛出异常</li>
<li>如果指定了type，则从上下文中找到类型匹配的唯一bean进行装配，找不到或者找到多个，都会抛出异常</li>
<li> 如果既没有指定name，又没有指定type，则自动按照byName方式进行装配（见2）；如果没有匹配，则回退为一个原始类型（UserDao）进行匹配，如果匹配则自动装配；</li>
</ol>
<p>1.6. @PostConstruct（JSR-250）<br />
在方法上加上注解@PostConstruct，这个方法就会在Bean初始化之后被Spring容器执行（注：Bean初始化包括，实例化Bean，并装配Bean的属性（依赖注入））。<br />
它的一个典型的应用场景是，当你需要往Bean里注入一个其父类中定义的属性，而你又无法复写父类的属性或属性的setter方法时，如：</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li>public class UserDaoImpl extends HibernateDaoSupport implements UserDao {</li>
<li> private SessionFactory mySessionFacotry;</li>
<li> <span style="color: #646464;">@Resource</span></li>
<li> public void setMySessionFacotry(SessionFactory sessionFacotry) {</li>
<li> this.mySessionFacotry = sessionFacotry;</li>
<li> }</li>
<li> <span style="color: #646464;">@PostConstruct</span></li>
<li> public void injectSessionFactory() {</li>
<li> super.setSessionFactory(mySessionFacotry);</li>
<li> }</li>
<li> &#8230;</li>
<li>}</li>
</ol>
</div>
<pre>public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
 private SessionFactory mySessionFacotry;
 @Resource
 public void setMySessionFacotry(SessionFactory sessionFacotry) {
  this.mySessionFacotry = sessionFacotry;
 }
 @PostConstruct
 public void injectSessionFactory() {
  super.setSessionFactory(mySessionFacotry);
 }
 ...
}</pre>
<p>这里通过@PostConstruct，为UserDaoImpl的父类里定义的一个sessionFactory私有属性，注入了我们自己定义的 sessionFactory（父类的setSessionFactory方法为final，不可复写），之后我们就可以通过调用 super.getSessionFactory()来访问该属性了。</p>
<p>1.7. @PreDestroy（JSR-250）<br />
在方法上加上注解@PreDestroy，这个方法就会在Bean初始化之后被Spring容器执行。由于我们当前还没有需要用到它的场景，这里不不去演示。其用法同@PostConstruct。</p>
<p>1.8. 使用&lt;context:annotation-config /&gt;简化配置<br />
Spring2.1添加了一个新的context的Schema命名空间，该命名空间对注释驱动、属性文件引入、加载期织入等功能提供了便捷的配置。我们 知道注释本身是不会做任何事情的，它仅提供元数据信息。要使元数据信息真正起作用，必须让负责处理这些元数据的处理器工作起来。<br />
AutowiredAnnotationBeanP</p>
<div>ostProcessor和CommonAnnotationBeanPostProcessor 就是处理这些注释元数据的处理器。但是直接在Spring配置文件中定义这些Bean显得比较笨拙。Spring为我们提供了一种方便的注册这些 BeanPostProcessor的方式，这就是&lt;context:annotation-config /&gt;：</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li>&lt;beans xmlns=&#8221;http://www.springframework.org/schema/beans&#8221; xmlns:xsi=&#8221;http://www.w3.org/2001/XMLSchema-instance&#8221; xmlns:context=&#8221;http://www.springframework.org/schema/context&#8221;</li>
<li> xsi:schemaLocation=&#8221;http://www.springframework.org/schema/beans</li>
<li> http://www.springframework.org/schema/beans/spring-beans-2.5.xsd</li>
<li> http://www.springframework.org/schema/context</li>
<li> http://www.springframework.org/schema/context/spring-context-2.5.xsd&#8221;&gt;</li>
<li> &lt;context:annotation-config /&gt;</li>
<li> &lt;/beans&gt;</li>
</ol>
</div>
<pre>&lt;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"&gt;
 &lt;context:annotation-config /&gt;
&lt;/beans&gt;</pre>
<p>&lt;context:annotationconfig /&gt;将隐式地向Spring容器注册AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、 PersistenceAnnotationBeanPostProcessor以及RequiredAnnotationBeanPostProcessor这4个BeanPostProcessor。</p>
<p>2. 使用Spring注解完成Bean的定义<br />
以上我们介绍了通过@Autowired或@Resource来实现在Bean中自动注入的功能，下面我们将介绍如何注解Bean，从而从XML配置文件中完全移除Bean定义的配置。</p>
<p>2.1. @Component（不推荐使用）、@Repository、@Service、@Controller<br />
只需要在对应的类上加上一个@Component注解，就将该类定义为一个Bean了：</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li><span style="color: #646464;">@Component</span></li>
<li>public class UserDaoImpl extends HibernateDaoSupport implements UserDao {</li>
<li> &#8230;</li>
<li>}</li>
</ol>
</div>
<pre>@Component
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
 ...
}</pre>
<p>使用@Component注解定义的Bean，默认的名称（id）是小写开头的非限定类名。如这里定义的Bean名称就是userDaoImpl。你也可以指定Bean的名称：<br />
@Component(&#8220;userDao&#8221;)<br />
@Component是所有受Spring管理组件的通用形式，Spring还提供了更加细化的注解形式：@Repository、@Service、 @Controller，它们分别对应存储层Bean，业务层Bean，和展示层Bean。目前版本（2.5）中，这些注解与@Component的语义 是一样的，完全通用，在Spring以后的版本中可能会给它们追加更多的语义。所以，我们推荐使用@Repository、@Service、 @Controller来替代@Component。</p>
<p>2.2. 使用&lt;context:component-scan /&gt;让Bean定义注解工作起来</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li>&lt;beans xmlns=&#8221;http://www.springframework.org/schema/beans&#8221; xmlns:xsi=&#8221;http://www.w3.org/2001/XMLSchema-instance&#8221; xmlns:context=&#8221;http://www.springframework.org/schema/context&#8221;</li>
<li> xsi:schemaLocation=&#8221;http://www.springframework.org/schema/beans</li>
<li> http://www.springframework.org/schema/beans/spring-beans-2.5.xsd</li>
<li> http://www.springframework.org/schema/context</li>
<li> http://www.springframework.org/schema/context/spring-context-2.5.xsd&#8221;&gt;</li>
<li> &lt;context:component-scan base-package=&#8221;com.kedacom.ksoa&#8221; /&gt;</li>
<li> &lt;/beans&gt;</li>
</ol>
</div>
<pre>&lt;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"&gt;
 &lt;context:component-scan base-package="com.kedacom.ksoa" /&gt;
&lt;/beans&gt;</pre>
<p>这里，所有通过&lt;bean&gt;元素定义Bean的配置内容已经被移除，仅需要添加一行&lt;context:component-scan /&gt;配置就解决所有问题了——Spring XML配置文件得到了极致的简化（当然配置元数据还是需要的，只不过以注释形式存在罢了）。&lt;context:component-scan /&gt;的base-package属性指定了需要扫描的类包，类包及其递归子包中所有的类都会被处理。<br />
&lt;context:component-scan /&gt;还允许定义过滤器将基包下的某些类纳入或排除。Spring支持以下4种类型的过滤方式：</p>
<ul>
<li>过滤器类型 表达式范例 说明</li>
<li>注解 org.example.SomeAnnotation 将所有使用SomeAnnotation注解的类过滤出来</li>
<li>类名指定 org.example.SomeClass 过滤指定的类</li>
<li>正则表达式 com\.kedacom\.spring\.annotation\.web\..* 通过正则表达式过滤一些类</li>
<li>AspectJ表达式 org.example..*Service+ 通过AspectJ表达式过滤一些类</li>
</ul>
<p>以正则表达式为例，我列举一个应用实例：</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li>&lt;context:component-scan base-package=&#8221;com.casheen.spring.annotation&#8221;&gt;</li>
<li> &lt;context:exclude-filter type=&#8221;regex&#8221; expression_r=&#8221;com\.casheen\.spring\.annotation\.web\..*&#8221; /&gt;</li>
<li> &lt;/context:component-scan&gt;</li>
</ol>
</div>
<pre>&lt;context:component-scan base-package="com.casheen.spring.annotation"&gt;
  &lt;context:exclude-filter type="regex" expression_r="com\.casheen\.spring\.annotation\.web\..*" /&gt;
 &lt;/context:component-scan&gt;</pre>
<p>值得注意的是&lt;context:component-scan /&gt;配置项不但启用了对类包进行扫描以实施注释驱动Bean定义的功能，同时还启用了注释驱动自动注入的功能（即还隐式地在内部注册了AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor），因此当使用&lt;context:component-scan /&gt;后，就可以将&lt;context:annotation-config /&gt;移除了。</p>
<p>2.3. 使用@Scope来定义Bean的作用范围<br />
在使用XML定义Bean时，我们可能还需要通过bean的scope属性来定义一个Bean的作用范围，我们同样可以通过@Scope注解来完成这项工作：</p>
<div>
<div>
<div>Java代码</div>
</div>
<ol>
<li><span style="color: #646464;">@Scope</span>(&#8220;session&#8221;)</li>
<li><span style="color: #646464;">@Component</span>()</li>
<li>public class UserSessionBean implements Serializable {</li>
<li> &#8230;</li>
<li>}</li>
</ol>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-annotation-630/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>用Spring 2.0和AspectJ简化企业应用程序</title>
		<link>http://javadou.com/spring-2-0-aspectj-552/</link>
		<comments>http://javadou.com/spring-2-0-aspectj-552/#comments</comments>
		<pubDate>Sun, 21 Mar 2010 02:46:38 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[aspectj]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=552</guid>
		<description><![CDATA[用Spring 2.0和AspectJ简化企业应用程序 Spring：简单而强大 Spring的目标是使企业应用程序开发尽可能地简单和高效。这一 理论的实例可以从Spring的JDBC、ORM、JMX、依赖注入等方法，以及企业应用程序开发的其他许多重要... ]]></description>
			<content:encoded><![CDATA[<p>用Spring 2.0和AspectJ简化企业应用程序</p>
<p>Spring：简单而强大</p>
<p>Spring的目标是使企业应用程序开发尽可能地简单和高效。这一 理论的实例可以从Spring的JDBC、ORM、JMX、依赖注入等方法，以及企业应用程序开发的其他许多重要领域中见到。Spring还区分了使事情 简单化和过分单纯化之间的差异。最不可思议的是同时提供了简单化和强大的功能。企业应用程序中复杂性的一个根源来自影响应用程序多个部分的特性和需求的实 现。相关于这些特性的代码最终散布在应用程序代码中，使得它更难以添加、维护和理解。Spring 2.0使得以模块化的方式实现这些特性变得更加简单，极大地简化了整体的应用程序代码，并且有时使得在实现没有它的情况下十分痛苦的编码需求变得易如反 掌。</p>
<p>事务管理是影响应用程序多个部分的一个特性实例：一般来说所有的操作都在服务层。在Spring中解决这种需求的方式是通过使用 AOP。Spring 2.0在它对AOP的支持中提供了一个明显的简化，同时还提供了比Spring 1.x所提供的更多富有表现力的功能。这些改善之处主要来自两个主要的领域：通过使用XML schema极大地简化了配置，以及与AspectJ的整合带来了更好的富有表现力的功能和更简单的advice模型。</p>
<p>在本文中，我将首先 介绍在典型的企业应用程序中，Spring AOP和AspectJ适用于什么地方，之后介绍在2.0中新的Spring AOP支持。大部分篇幅用来讲解企业应用程序中AOP的采用路线图，通过大量可以只用AOP实现的特性实例，但是用任何其他的方法进行实现都将非常困难。</p>
<p>简化企业应用程序</p>
<p>典型的企业应用程序——比如一个Web应用程序——由许多层构成。一个包含视图和控制器的Web层，一个表现系统业务接口的服务层，一个负责保存和获取持久化领域对象的数据访问或者存储层，与所有这些层共事的，还有一个核心业务逻辑所在的领域模型。</p>
<p>Web 层、服务层和数据访问层有着许多相同的重要特征：它们应该尽可能地瘦，它们不应该包含业务逻辑，并且它们一般通过Spring组装在一起。在这些层中， Spring负责创建对象和配置。领域模型则有些不同：领域对象由程序员利用新的操作器创建（或者利用从数据库中获取的ORM工具进行扩建）。领域对象有 许多唯一的实例，它们（可以）有丰富的行为。</p>
<p>服务层可以包含特定于应用程序用例的逻辑，但是所有领域相关的逻辑都应该放在领域模型本身里面。</p>
<p>服务层一般是使用声明式企业服务（例如事务）的地方。声明式的企业服务，例如事务和安全是影响应用程序中多个点的很好的需求实例。事实上，即使你想让（比如）事务划分只在单个地方，将这项功能与你的应用程序逻辑分开，使得代码更加简单，避免不必要的耦合，这也仍然很好。</p>
<p>由 于服务对象是Spring管理的bean，Spring AOP天生适合于在这个层中处理需求。事实上，任何人在使用Spring的声明式事务支持时，就已经是在使用Spring AOP了，无论他们是否意识到这一点。Spring AOP很成熟，得到了广泛的应用。它非常适合于Web、服务和数据访问层中受Spring管理的bean，只要你的需求可以通过advice bean方法执行得到处理（且这些层的许多用例都属于这一类）。</p>
<p>当提到影响你领域模型中多个点的需求时，你应用程序的最重要部分——Spring AOP——的帮助就小多了。你可以编 程式地使用Spring AOP，但是这样会很难使用，并且还要你自己负责创建代理和管理同一性。AspectJ天生适合于实现影响领域对象的特性。AspectJ方面不需要任何 特殊的代理创建，并且可以很恰当地通知运行时在你的应用程序代码中，或者通过你可能使用的框架所创建的对象。当你想要模块化影响你应用程序的所有不同层的 行为，或者模块化性能以任何方式感知的行为时，AspectJ也是一种非常好的解决方案。</p>
<p>因此，我们最想要的是一种一致的Spring AOP和AspectJ方法，以便我们可以很容易地一起使用这两种工具，以便如果需求发生变化，你用（比如）Spring AOP开发的能力就可以转移到AspectJ上。无论我们正在使用哪种组合，我们仍然喜欢依赖注入和Spring所提供的配置的所有益处。Spring 2.0中新的AOP支持正好带来了这一点。</p>
<p>底层的技术：AspectJ和Spring AOP简介</p>
<p>AOP使得实现在应用程序中影响多个点的特性变得更加简单。这主要因为AOP提供了对名为通知（advice）的这个东西的支持。通知不同于必须显式调用的方法，每当发生匹配的触发事件时，它就自动地执行。继续事务主题，触发事件是服务层中一个方法的执行，并且通知逻辑提供所需的事务划分。用AOP的话来说，触发事件被称作连接点（join point），而切入点表达式（pointcut expression）则 用来选择通知要在那里运行的连接点。这个简单的倒置意味着不用将调用散布到你全部应用程序代码中的事务管理器，而是只要编写一个切入点表达式，定义你需要 事务管理器在什么地方完成某事的所有点，并将它与适当的通知关联起来。AspectJ和Spring AOP提供对这个模型的支持，事实上，它们有着完全相同的切入点表达语言。</p>
<p>在接下来的讨论中，注意Spring和AspectJ保持为独立 的工程，这很重要。Spring只使用反射和由AspectJ 5作为一个库所暴露的工具API。Spring 2.0仍然是一个运行时基于代理的框架，且AspectJ织入器（weaver）不用于Spring方面。</p>
<p>我相信你们中大多数人都知道， AspectJ是一种包含完整编译器的语言（构建为Eclipse JDT Java编译器的一个扩展），对离线或者在运行时将（与）二进制的class文件（链接的方面）作为类织入的支持，被加载到了虚拟机中。AspectJ的 最新发布版本是AspectJ 5，它为Java 5语言提供完整的支持。</p>
<p>AspectJ 5也引入了方面声明的第二种风格，我们称之为“@AspectJ”，它允许你将一个方面编写为一个包含注解的Java类。这种方面可以通过一般的Java 5编译器进行编译。例如，传统的“HelloWorld”方面在AspectJ编程语言中看起来像这样：</p>
<pre>public aspect HelloFromAspectJ {

  pointcut mainMethod() : execution(* main(..));

  after() returning : mainMethod() {
    System.out.println("Hello from AspectJ!);
  }

}</pre>
<p>与传统的HelloWorld类共同编译这个方面，当你运行应用程序时，会看到这样的输出：</p>
<p>Hello World!</p>
<p>Hello from AspectJ!</p>
<p>我们可以用@Aspect风格编写相同的方面如下：</p>
<pre>@Aspect
public class HelloFromAspectJ {

  @Pointcut("execution(* main(..))")
  public void mainMethod() {}

  @AfterReturning("mainMethod()")
  public void sayHello() {
    System.out.println("Hello from AspectJ!");
  }

}</pre>
<p>就 本文而言，AspectJ 5中另一项重要的新特性是一个完全AspectJ感知的反射API（你可以在运行时为它的通知和切入点成员等等请求一个方面），和让第三方使用 AspectJ的切入点解析和匹配引擎的工具API。这些API的第一大用户，就像你很快会见到的，是Spring AOP。</p>
<p>与AspectJ 相反，Spring AOP是一个基于代理的运行时框架。在使用Spring AOP时，并没有特殊的工具或者构建需求，因而Spring AOP是一种很容易开始的方法。作为一种基于代理的框架，它既有优点也有缺点。除了已经提到过的容易使用的因素之外，基于代理的框架还能够独立地通知相同 类型的不同实例。将这一点与AspectJ基于类型的语义相比，在这里，类型的每一个实例都有着相同的行为。对于像Spring这样的框架而言，能够独立 地通知独立的对象（Spring beans）是一个重要的必要条件。另一方面，Spring AOP只支持AspectJ功能的一个子集：有可能在Spring beans中通知方法的执行，但是其他没什么。</p>
<p>基于代理的框架一般会有 同一性的问题：有两个对象（代理和目标）都表示应用程序中的同一个实体。必须始终小心地传递适当的引用，确保给实例化过的任何新的目标对象创建代理。 Spring AOP通过管理bean实例化（以便代理可以被透明地创建）和通过依赖注入（以便Spring始终可以注入适当的引用），巧妙地解决了这些问题。</p>
<p>Spring 2.0中新的AOP支持</p>
<p>2.0 中的Spring AOP可以完全向后与Spring 1.x应用程序和配置兼容。它还提供了比Spring 1.x更简单且更强大的配置。新的AOP支持是基于schema的，因此在你的Spring beans配置文件中将需要相关的命名空间和schema定位属性。它看起来像这样：</p>
<pre>&lt;beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation=
     "http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/aop

      http://www.springframework.org/schema/aop/spring-aop.xsd"&gt;

 ...

&lt;/beans&gt;</pre>
<p>与使用DTD时所需要的更简单的xml配置相比，那么目前为止我们还没有超越——但这是标准的xml配置，并且可以在你的IDE中的一个模板里创建，并且只在每当你需要创建一个Spring配置时才被重用。当我们开始将一些内容添加到配置中时，你会领略到这一好处。</p>
<p>Spring 2.0默认使用AspectJ 切入点语言（受执行连接点种类的限制）。如果它看到一个AspectJ 切入点表达式，它就调出AspectJ对它进行解析和匹配。这意味着你用Spring AOP编写的任何切入点表达式都将以与AspectJ完全相同的方式进行工作。此外，Spring实际上能理解@AspectJ方面，因此有可能共用 Spring和AspectJ之间完整的方面定义。激活这项功能很容易，只要将&lt;aop:aspectj-autoproxy&gt;元素包括在你 的配置中。如果AspectJ自动代理以这种方式激活，那么在你的应用程序上下文中定义的、包含@AspectJ方面的任何bean，都将被Spring AOP视为一个方面，并将相应地通知上下文中的bean。</p>
<p>下面是当你以这种方式使用Spring AOP时的Hello World程序。首先，应用程序上下文文件中bean元素的内容：</p>
<pre>&lt;bean id="helloService"
    class="org.aspectprogrammer.hello.spring.HelloService"/&gt;

 &lt;aop:aspectj-autoproxy/&gt;

 &lt;bean id="helloFromAspectJ"

    class="org.aspectprogrammer.hello.aspectj.HelloFromAspectJ"/&gt;</pre>
<p>HelloService是一个简单的Java类：</p>
<pre>public class HelloService {

  public void main() {
    System.out.println("Hello World!");
  }

}</pre>
<p>HelloFromAspectJ与你在本文前面见过的被注解的Java类（@AspectJ方面）完全相同。以下是启动Spring容器的一个小主类，获得一个对helloService bean的引用，并在它上面调用’main’方法：</p>
<pre>public class SpringBoot {

  public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext(
      "org/aspectprogrammer/hello/spring/application-context.xml");
    HelloService service = (HelloService) context.getBean("helloService");
    service.main();
  }

}</pre>
<p>运行这个程序产生下面的输出：</p>
<p>Hello World!</p>
<p>Hello from AspectJ!</p>
<p>记住，这仍然是Spring AOP（我们根本没有在使用AspectJ编译器或者织入器），但它是提供关于@AspectJ方面的反射信息和解析并匹配代表Spring的切入点的AspectJ。</p>
<p>Spring 2.0还支持用一个简单的POJO支持的方面声明的一种xml形式（不需要任何注解）。xml形式也使用相同的AspectJ 切入点语言子集，并支持相同的五种AspectJ 通知类型（前置通知（before advice）、后置通知（after returning advice）、异常通知（after throwing advice）、后通知（after [finally] advice）和 环绕通知（around advice））。</p>
<p>下面是使用一个基于XML的方面声明的hello world应用程序：</p>
<pre> &lt;bean id="helloService"
      class="org.aspectprogrammer.hello.spring.HelloService"/&gt;

   &lt;aop:config&gt;
     &lt;aop:aspect ref="helloFromSpringAOP"&gt;
 &lt;aop:pointcut id="mainMethod" expression="execution(* main(..))"/&gt;
 &lt;aop:after-returning pointcut-ref="mainMethod" method="sayHello"/&gt;

     &lt;/aop:aspect&gt;
   &lt;/aop:config&gt;

   &lt;bean id="helloFromSpringAOP"
         class="org.aspectprogrammer.hello.spring.HelloAspect"/&gt;</pre>
<p>aop 命名空间中的元素可以用来声明方面、切入点和通知，有着与它们的AspectJ和@AspectJ等效物完全相同的语义。“aspect”元素引用 Spring bean（完全由Spring配置和实例化），并且每个通知元素都在该bean中指定将被调用来执行通知的方法。在这个例子中，HelloAspect类 只是：</p>
<pre>public class HelloAspect {

  public void sayHello() {
    System.out.println("Hello from Spring AOP!");
  }

}</pre>
<p>运行程序将产生熟悉的输出：</p>
<p>Hello World!</p>
<p>Hello from Spring AOP!</p>
<p>如果你还没有编写过这样的程序，就下载Spring 2.0，亲自尝试一下，这可是个好主意。</p>
<p>我 不想把本文变成是关于Spring AOP的一个完全的教程，而是想要加紧看一些可以有效地以这种方式实现的特性实例。我将只是指出，传递Spring从使用AspectJ 切入点语言中获得的其中某个东西，是编写静态类型的通知（声明它们真正需要的那些参数的方法）的能力，与始终使用非类型的Object数组相反——这使得 通知方法更容易编写。</p>
<p>采用路线图</p>
<p>理论说得够多了……让我们看一下你在企业应用程序中实际上如何以及为什么要使用AOP的一些例子。开始AOP，并不一定是一种肯定一切或者否定一切的爆炸性方法。采用可以分阶段进行，每个阶段都为增加的技术暴露回报以更多的益处。</p>
<p>建 议的采用路线图是只开始使用Spring提供的开箱即用的方面（例如事务管理）。许多Spring用户将已经在这么做了，但多半不太欣赏AOP被“背地 里”使用着。根据这一点，你可以实现在使用Spring AOP的Web、服务和数据访问层中可能会有的任何定制横切需求。</p>
<p>实现影响领域模 型的特性必需使用AspectJ。你听到这句话时可能感到惊讶：有大量的AspectJ方面对于你在开发时都非常有帮助，而且不影响在产品中以任何方式运 行的应用程序。这些方面可以增加很多价值，并且采用风险非常小，因此建议用它们开始AspectJ。根据这一点，你可以选择通过AspectJ实现“基础 结构的”需求——典型的实例为剖析（profiling）、跟踪（tracing）、错误处理（error-handling）等等。随着你越来越习惯于 AspectJ和所配套的工具，最终你可以用方面在领域逻辑自身中开始实现功能。</p>
<p>关于AOP采用路线图的其他信息，请见《Eclipse AspectJ》一书中的第11章，或者developerWorks AOP@Work系列中“Next steps with aspects”一文。这两个资源都专门关注AspectJ，而我在这里则正在讨论同时使用Spring和AspectJ。</p>
<p>让我们依次看一下这每一种采用阶段。</p>
<p>当 在一个工程中使用AOP时，首先要做的最有意义的事是定义一组切入点表达式，描述你应用程序中的不同模块或者层。这些切入点表达式在采用的所有不同阶段中 都将很有帮助，并且定义一次将减少重复，改善代码的清晰度。如果我们用@AspectJ符号编写这些切入点，它们就可以通过任何常规的Java 5编译器进行编译。利用一般的AspectJ语言关键字也可能编写相同的东西，用ajc编译源文件，并将生成的.class文件添加到classpath 中。我将用@AspectJ作为开始Spring AOP的两种方法中更为容易的那一种。许多读者将会熟悉Spring所携带的“jpetstore”范例应用程序。我已经稍微重写了这个应用程序，给它增 加了一些方面（本文稍后会讨论到）。以下是在pet store中捕捉主要层和模块的“SystemArchitecture”方面的开头部分：</p>
<pre>@Aspect
public class SystemArchitecture {

 /**
     *  we're in the pet store application if we're within any
     *  of the pet store packages
     */
 @Pointcut("within(org.springframework.samples.jpetstore..*)")
        public void inPetStore() {}

 // modules
 // ===========

 @Pointcut("within(org.springframework.samples.jpetstore.dao..*)")
        public void inDataAccessLayer() {}

 @Pointcut("within(org.springframework.samples.jpetstore.domain.*)")
        public void inDomainModel() {}

 @Pointcut("within(org.springframework.samples.jpetstore.service..*)")
        public void inServiceLayer() {}

 @Pointcut("within(org.springframework.samples.jpetstore.web..*)")
        public void inWebLayer() {}

 @Pointcut("within(org.springframework.samples.jpetstore.remote..*)")
        public void inRemotingLayer() {}

 @Pointcut("within(org.springframework.samples.jpetstore.validation..*)")
        public void inValidationModule() {}

 // module operations
 // ==================

 @Pointcut("execution(* org.springframework.samples.jpetstore.dao.*.*(..))")
        public void doaOperation() {}

 @Pointcut("execution(* org.springframework.samples.jpetstore.service.*.*(..))")
        public void businessService() {}

 @Pointcut("execution(public * org.springframework.samples.jpetstore.validation.*.*(..))")
 public void validation() {}

}</pre>
<p>既然我们已经有了谈论应用程序（“inServiceLayer”、“businessOperation”等等）的术语，让我们用它来做一些有意义的事情吧。</p>
<p>使用开箱即用的Spring方面</p>
<p>advisor是Spring 1.x遗留下来的一个Spring概念，它包含了一个非常小的方面，带有单独的一条通知，和关联的切入点表达式。对于事务划分而言，advisor就是我 们所需要的一切。典型的事务需求为：服务层中的所有操作都要利用（几个）底层资源管理器的默认隔离级别在一个事务（REQUIRED语义）中执行。此外， 一些操作可以被标识为“只读”事务——这一知识可以给这类事务带来明显的性能改善。jpestore advisor声明如下：</p>
<pre>&lt;!--
   all aspect and advisor declarations are gathered inside an
   aop:config element
--&gt;
&lt;aop:config&gt;

  &lt;aop:advisor
    pointcut="org.springframework.samples.jpetstore.SystemArchitecture.businessService()"
    advice-ref="txAdvice"/&gt;

&lt;/aop:config&gt;</pre>
<p>这 个声明仅仅意味着：当执行一个“businessService”时，我们需要运行被“txAdvice”引用的通知。 “BusinessService”切入点在我们前面讨论过的 org.springframework.samples.jpetstore.SystemArchitecture方面中定义。它与在服务接口中定义 的任何操作的执行相匹配。由于事务通知本身可能需要相当多的配置，因此Spring在tx命名空间中提供了tx:advice元素，使得这项工作变得更加 简单和清晰。这就是给jpetstore应用程序的“txAdvice”定义：</p>
<pre>&lt;!--
  Transaction advice definition, based on method name patterns.
  Defaults to PROPAGATION_REQUIRED for all methods whose name starts with
  "insert" or "update", and to PROPAGATION_REQUIRED with read-only hint
  for all other methods.
--&gt;

&lt;tx:advice id="txAdvice"&gt;
  &lt;tx:attributes&gt;
    &lt;tx:method name="insert*"/&gt;
    &lt;tx:method name="update*"/&gt;
    &lt;tx:method name="*" read-only="true"/&gt;

  &lt;/tx:attributes&gt;
&lt;/tx:advice&gt;</pre>
<p>还有一种更加简单的方法来配置使用注解的事务。在使用@Transactional注解时，你唯一需要的XML是：</p>
<pre>&lt;!--
   Tell Spring to apply transaction advice based on the presence of
   the @Transactional annotation on Spring bean types.
--&gt;
&lt;tx:annotation-driven/&gt;</pre>
<p>使用注解方法时，PetService实现要做如下注解：</p>
<pre>/*
 * all operations have TX_REQUIRED, default isolation level,
 * read-write transaction semantics by default
 */
@Transactional
public class PetStoreImpl implements PetStoreFacade, OrderService {

  ...

  /**
   * override defaults on a per-method basis
   */
  @Transactional(readOnly=true)
  public Account getAccount(String username) {
    return this.accountDao.getAccount(username);
  }

  ...

}</pre>
<p>简化Web、服务和数据访问层</p>
<p>Spring AOP可以用来简化Web、服务和数据访问层。在本节中，我们要看两个实例：一个取自数据访问层，一个取自服务层。</p>
<p>假 设你已经用Hibernate 3而不是用Spring HibernateTemplate支持类实现了你的数据访问层。你现在准备开始在应用程序中使用Spring，想要在服务层中利用Spring的细粒度 DataAccessException层次结构。Spring的HibernateTemplate将自动为你把 HibernateExceptions转换成DataAccessExceptions，但是由于现阶段你已经有一个非常满意的数据层实现，因此并不想 马上用Spring支持类对它进行重写。这意味着你需要自己实现异常转换。这个需求声明起来很简单：</p>
<p>从数据访问层中抛出任何HibernateException之后，在将它递给调用者之前将它转换成一个DataAccessException。</p>
<p>利用AOP，实现几乎与需求声明一样简单。没有AOP时实现这个需求是件非常令人头痛的事。这就是“myapp”的HibernateExceptionTranslator方面：</p>
<pre>@Aspect
public class HibernateExceptionTranslator {

  private HibernateTemplate hibernateTemplate;

  public void setHibernateTemplate(HibernateTemplate aTemplate) {
    this.hibernateTemplate = aTemplate;
  }

  @AfterThrowing(
    throwing="hibernateEx",
    pointcut="org.aspectprogrammer.myapp.SystemArchitecture.dataAccessOperation()"

  )
  public void rethrowAsDataAccessException(HibernateException hibernateEx) {
    throw this.hibernateTemplate
       .convertHibernateAccessException(hibernateEx);

  }

}</pre>
<p>方 面需要一个HibernateTemplate，以便执行转换——我们要用依赖注入对它进行配置，就像任何其他的Spring bean一样。通知声明应该有望非常容易地理解为需求声明的一个直接转换：“@AfterThrowing从dataAccessOperation() 操作中抛出一个HibernateException (hibernateEx) ，并重新抛出 rethrowAsDataAccessException”。简单而有力！</p>
<p>我们现在可以用ajc（AspectJ编译器）构建应用程序，这样我们就完事了。但是这里不需要使用ajc，因为Spring AOP也能识别@AspectJ方面。</p>
<p>在应用程序上下文文件中，我们需要两个配置。首先我们要告诉Spring，包含@AspectJ方面的类型的任何bean都应该用来配置Spring AOP代理。这是通过在应用程序上下文配置文件中的任何位置声明下列元素来实现的一个一次性配置：</p>
<p>&lt;aop:aspectj-autoproxy&gt;</p>
<p>然后我们需要声明异常转换bean，并对它进行配置，就像对待任何一般的Spring bean一样（这里并没有任何特定于AOP的东西）：</p>
<pre>&lt;bean id="hibernateExceptionTranslator"
   class="org.aspectprogrammer.myapp.dao.hibernate.HibernateExceptionTranslator"&gt;
  &lt;property name="hibernateTemplate"&gt;
    &lt;bean class="org.springframework.orm.hibernate3.HibernateTemplate"&gt;

      &lt;constructor-arg index="0" ref="sessionFactory" /&gt;
    &lt;/bean&gt;
  &lt;/property&gt;
&lt;/bean&gt;</pre>
<p>仅仅因为bean的类（HibernateExceptionTranslator）是一个@AspectJ方面，就足以配置Spring AOP了。</p>
<p>为了完整起见，我们也看一下如何用方面声明的xml形式来完成这项工作（例如对于在JDK 1.4下进行工作的）。hibernateExceptionTranslator的bean定义与上面所述的一样。类本身不再被注解，但是它剩下的部分也完全相同：</p>
<pre>public class HibernateExceptionTranslator {

  private HibernateTemplate hibernateTemplate;

  public void setHibernateTemplate(HibernateTemplate aTemplate) {
    this.hibernateTemplate = aTemplate;
  }

  public void rethrowAsDataAccessException(HibernateException hibernateEx) {
    throw this.hibernateTemplate
       .convertHibernateAccessException(hibernateEx);

  }

}</pre>
<p>由于这不再是一个@AspectJ方面，我们无法使用aspectj-autoproxy元素，而是用XML定义该方面：</p>
<pre>&lt;aop:config&gt;

  &lt;aop:aspect ref="hibernateExceptionTranslator"&gt;
     &lt;aop:after-throwing
         throwing="hibernateEx"

         pointcut="org.aspectprogrammer.myapp.SystemArchitecture.dataAccessOperation()"
         method="rethrowAsDataAccessException"/&gt;
  &lt;/aop:aspect&gt;

&lt;/aop:config&gt;</pre>
<p>这 看起来与前一个版本一样：after-throwing 从dataAccessOperation操作中抛出hibernateEx，并且重新抛出rethrowAsDataAccessException。 注意aop:aspect元素的“ref”属性，它引用了我们前面定义的hibernateExceptionTranslator bean。这是rethrowAsDataAccessException方法将要在那里被调用的bean实例，而hibernateEx则是在该方法中 声明的参数名（这个例子中的唯一参数）。就是这样。我们已经实现了需求（两次！）。利用@AspectJ风格，我们有15个非空的代码行，和一行XML。 这足以为我们在整个数据访问层中提供一致、正确的行为，但是它可能很大。</p>
<p>这个特殊方面的一大好处在于，如果你以后想要将数据层移植到一个基 于利用Hibernate的实现、或者任何其他JPA实现的JPA（EJB 3持久化），你的服务层将不会受到影响，并且可以继续使用DataAccessExceptions（Spring将为JPA提供模板和异常转换，就像对 其他的ORM实现所做的一样）。</p>
<p>既然我们可以在服务层中使用细粒度的DataAccessExceptions了，就可以利用这一点做些有意义的事情。让我们在将失败传递给客户端之前，实现由于并发失败而失败的任何等幂服务操作都将被透明地重试可设定次数的横切需求。</p>
<p>以下是完成这项工作的一个方面：</p>
<pre>@Aspect
public class ConcurrentOperationExecutor implements Ordered {

  private static final int DEFAULT_MAX_RETRIES = 2;
  private int maxRetries = DEFAULT_MAX_RETRIES;
  private int order = 1;
  private boolean retryOnOptimisticLockFailure = false;

  /**
   * configurable number of retries
   */
  public void setMaxRetries(int maxRetries) {
    this.maxRetries = maxRetries;
  }

  /**
   * Whether or not optimistic lock failures should also be retried.
   * Default is not to retry transactions that fail due to optimistic
   * locking in case we overwrite another user's work.
   */
  public void setRetryOnOptimisticLockFailure(boolean retry) {
     this.retryOnOptimisticLockFailure = retry;
  }

  /**
   *  implementing the Ordered interface enables us to specify when
   *  this aspect should run with respect to other aspects such as
   *  transaction management. We give it the highest precedence
   *  (1) which means that the retry logic will wrap the transaction
   *  logic - we need a fresh transaction each time.
   */
  public int getOrder() {
    return this.order;
  }

  public void setOrder(int order) {
    this.order = order;
  }

  /**
   * For now, just assume that all business services are idempotent
   */
  @Pointcut("org.aspectprogrammer.myapp.SystemArchitecture.businessService()")
  public void idempotentOperation() {}

  @Around("idempotentOperation()")
  public Object doConcurrentOperation(ProceedingJoinPoint pjp)
  throws Throwable {
    int numAttempts = 0;
    ConcurrencyFailureException failureException;
    do {
      try {
     return pjp.proceed();
      }
      catch(OptimisticLockingFailureException ex) {
        if (!this.retryOnOptimisticLockFailure) {
          throw ex;
        }
        else {
      failureException = ex;
     }
      }
      catch(ConcurrencyFailureException ex) {
         failureException = ex;
      }
    }
    while(numAttempts++ &lt; this.maxRetries);
      throw lockFailureException;
    }

}</pre>
<p>这 个方面还是可以被Spring AOP或者AspectJ使用，这一点不变。around advice (doConcurrentOperation)采用了类型ProceedingJoinPoint的一个特殊参数。当proceed在这个对象中被调用 时，无论“around”什么样的通知（在这个例子中为服务操作）都将执行。如果你去掉注释和样板getters-and-setters，这个方面的业 务端仍然只有32行代码。由于我们在配置文件中已经有aspectj-autoproxy元素，我们需要增加的就只是一个简单的bean定义了：</p>
<pre>&lt;bean id="concurrentOperationExecutor"
     class="org.aspectprogrammer.myapp.service.impl.ConcurrentOperationExecutor"&gt;
  &lt;property name="maxRetries" value="3"/&gt;

  &lt;property name="order" value="1"/&gt;
&lt;/bean&gt;</pre>
<p>如果服务层中并非所有的操作都是等幂的，该怎么办？我们如何判断等幂的操作呢？这就是切入点语言的威力开始显现之处。我们已经有一个表示等幂操作的概念的抽象：</p>
<pre>@Pointcut("org.aspectprogrammer.myapp.SystemArchitecture.businessService()")
  public void idempotentOperation() {}</pre>
<p>如果我们想要改变构成表示等幂操作的东西，我们所要做的就是改变切入点。例如，我们可以给等幂操作定义一个标识注解：@Idempotent。我们可以非常简单地将切入点表达式改为只与包含Idempotent注解的业务服务相匹配：</p>
<pre> @Pointcut(
    "org.aspectprogrammer.myapp.SystemArchitecture.businessService() &amp;&amp;
     @annotation(org.aspectprogrammer.myapp.Idempotent)")
  public void idempotentOperation() {}</pre>
<p>现在比使用APT简单一些了！切入点只说：“idempotentOperation是有着Idempotent 注解的businessService”。</p>
<p>希望你的大多数服务操作都是等幂的。在这种情况下，注解非等 幂的操作就可能比挑出等幂操作要容易得多。像@IrreversibleSideEffects这样的东西应该会成功。这在技术上和心理上都说得过去（指 想要用IrreversibleSideEffects对他们的代码进行注解的人！我宁愿重写代码而避免使用它们；）。由于 idempotentOperation的定义只有一处，很容易改变：</p>
<pre>@Pointcut(
    "org.aspectprogrammer.myapp.SystemArchitecture.businessService() &amp;&amp;
     !@annotation(org.aspectprogrammer.myapp.IrreversibleSideEffects)")
  public void idempotentOperation() {}</pre>
<p>idempotentOperation是一个没有IrreversibleSideEffects注解的businessService。</p>
<p>用开发时间方面提升生产力</p>
<p>一旦你习惯了给Spring AOP编写@AspectJ方面，就会从AspectJ中获得额外的益处，即使你只在开发期间使用它（并且在你正在运行的应用程序中没有AspectJ编 译的方面）。方面可以用来针对测试（它们使得某些模拟和错误注入变得更加容易）、调试和诊断问题，以及确保为你的应用程序所设计的设计指导方针得到实施。 首先，让我们看一个设计实施方面（enforcement aspects）的实例。继续在数据访问层中进行，我们现在要引入Spring HibernateTemplate，让Spring替我们管理Hibernate会话，而不用我们自己管理。以下这个方面将确保程序员不会忘记开始管理 他们自己的会话：</p>
<pre>public aspect SpringHibernateUsageGuidelines {

  pointcut sessionCreation()
    : call(* SessionFactory.openSession(..));

  pointcut sessionOrFactoryClose()
    : call(* SessionFactory.close(..)) ||
      call(* Session.close(..));

  declare error
   : sessionCreation() || sessionOrFactoryClose()
   : "Spring manages Hibernate sessions for you, " +
     "do not try to do it programmatically";
}</pre>
<p>有了这个方面之后，如果一位程序员在给Eclipse使用AspectJ Development Tools（AJDT） 插件，他或者她就将在问题视图中看到一个编译错误的标识，并在源代码中出错的位置（与任何一般的编译错误完全一样）会有错误文本：“Spring替你管理 Hibernate会话，请不要试图编程式地进行管理”（Spring manages Hibernate sessions for you, do not try to do it programmatically）。建议引入像这样的实施方面的方法是，将AspectJ编译步骤增加到用实施方面“织入”应用程序的构建过程——如果 被方面发现构建错误，这项任务将会失败。</p>
<p>现在让我们看一下简单的诊断方面（diagnosis aspect）。回顾一下我们曾将一些事务标识为只读（一项很重要的性能优化）。随着应用程序复杂性的增加，从概念上来说，从事务划分所发生的服务层操作 的位置，到作为指定用例的一部分而执行的业务领域逻辑，这之间可能十分遥远。如果在一个只读的事务期间，领域逻辑更新了一个领域对象的状态，我们就会有丢 失更新的风险（从来没有提交到数据库）。这可能成为那些莫名其妙bug的根源。</p>
<p>LostUpdateDetector方面可以在开发时间用来侦测可能的丢失更新。</p>
<pre>public aspect LostUpdateDetector {

  private Log log = LogFactory.getLog(LostUpdateDetector.class);

  pointcut readOnlyTransaction(Transactional txAnn) :
    SystemArchitecture.businessService() &amp;&amp;
    @annotation(txAnn) &amp;&amp; if(txAnn.readOnly());

  pointcut domainObjectStateChange() :
     set(!transient * *) &amp;&amp;

     SystemArchitecture.inDomainModel();

  ..</pre>
<p>我 已经通过在方面中定义两个有用的切入点开始了。readOnlyTransaction是有着@Transactional注解的 businessService()的执行，readOnly()属性设置为true。domainObjectStateChange是任何非瞬时领域 inDomainModel()的更新。（注意，这是进行了简化，但是对于组成一个领域对象状态变化的东西仍然很有用——我们可以将该方面扩展为处理集合 等等，如果我们希望如此的话）。利用所定义的这两个概念，我们现在就可以通过potentialLostUpdate()表达想说的话了：</p>
<pre>pointcut potentialLostUpdate() :
    domainObjectStateChange() &amp;&amp;
    cflow(readOnlyTransaction(Transactional));</pre>
<p>potentialLostUpdate 是在一个readOnlyTransaction（期间）的控制流中所做的一个domainObjectState变化。你从这里可以领略到切入点语言生 效的威力。通过组成两个具名的切入点表达式，我们已经能够非常简单地表达一个很强大的概念。与你只有一个粗糙的拦截模型可用时相比，利用切入点语言更容易 表达像potentialLostUpdate这样的条件。它也比像EJB 3所提供的那些过于单纯的拦截机制要强大得多。</p>
<p>最后，当发生potentialLostUpdate时，我们当然需要真正地做一些事情：</p>
<pre>after() returning : potentialLostUpdate() {
    logLostUpdate(thisJoinPoint);
  }

  private void logLostUpdate(JoinPoint jp) {
    String fieldName = jp.getSignature().getName();
    String domainType = jp.getSignature().getDeclaringTypeName();
    String newValue = jp.getArgs()[0].toString();
    Throwable t = new Throwable("potential lost update");
    t.fillInStackTrace();
    log.warn("Field [" +  fieldName + "] in type [" + domainType + "] " +
      "was updated to value [" + newValue + "] in a read-only " +
      "transaction, update will be lost.",t);
  }

}</pre>
<p>以下是有了这个方面之后，运行一个测试案例所得到的日志信息：</p>
<p>WARN &#8211; LostUpdateDetector.logLostUpdate(41) | Field [name] in type</p>
<p>[org.aspectprogrammer.myapp.domain.Pet] was updated to value [Mr.D.]</p>
<p>in a read-only transaction, update will be lost.</p>
<p>java.lang.Throwable: potential lost update</p>
<p>at org.aspectprogrammer.myapp.debug.LostUpdateDetector.logLostUpdate(LostUpdateDetector.aj:40)</p>
<p>at org.aspectprogrammer.myapp.debug.LostUpdateDetector.afterReturning(LostUpdateDetector.aj:32)</p>
<p>at org.aspectprogrammer.myapp.domain.Pet.setName(Pet.java:32)</p>
<p>at org.aspectprogrammer.myapp.service.impl.PetServiceImpl.updateName(PetServiceImpl.java:40)</p>
<p>at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:100)</p>
<p>at org.aspectprogrammer.myapp.service.impl.ConcurrentOperationExecutor.doConcurrentOperation(ConcurrentOperationExecutor.java:37)</p>
<p>at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)</p>
<p>at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)</p>
<p>at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)</p>
<p>作 为题外话，解释一下干净且易读的堆栈轨迹（和适当的乐观重试逻辑）。易读的堆栈轨迹（stack trace）是由于从异常堆栈轨迹项中去除了干扰的另一个方面。没有适当的堆栈轨迹管理方面，所有的Spring AOP拦截堆栈框也都被显示出来，出现了像下面所示这样的堆栈轨迹。我想，你会认同说简化版是一个很大的改进！</p>
<p>WARN &#8211; LostUpdateDetector.logLostUpdate(41) | Field [name] in type</p>
<p>[org.aspectprogrammer.myapp.domain.Pet] was updated to value [Mr.D.]</p>
<p>in a read-only transaction, update will be lost.</p>
<p>java.lang.Throwable: potential lost update</p>
<p>at org.aspectprogrammer.myapp.debug.LostUpdateDetector.logLostUpdate(LostUpdateDetector.aj:40)</p>
<p>at org.aspectprogrammer.myapp.debug.LostUpdateDetector.ajc$afterReturning$org_aspectprogrammer_myapp_debug_LostUpdateDetector$1$b5d4ce0c(LostUpdateDetector.aj:32)</p>
<p>at org.aspectprogrammer.myapp.domain.Pet.setName(Pet.java:32)</p>
<p>at org.aspectprogrammer.myapp.service.impl.PetServiceImpl.updateName(PetServiceImpl.java:40)</p>
<p>at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)</p>
<p>at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)</p>
<p>at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)</p>
<p>at java.lang.reflect.Method.invoke(Unknown Source)</p>
<p>at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:287)</p>
<p>at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:181)</p>
<p>at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:148)</p>
<p>at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:100)</p>
<p>at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)</p>
<p>at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:71)</p>
<p>at org.aspectprogrammer.myapp.service.impl.ConcurrentOperationExecutor.doConcurrentOperation(ConcurrentOperationExecutor.java:37)</p>
<p>at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)</p>
<p>at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)</p>
<p>at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)</p>
<p>at java.lang.reflect.Method.invoke(Unknown Source)</p>
<p>at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:568)</p>
<p>at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:558)</p>
<p>at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:57)</p>
<p>at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)</p>
<p>at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)</p>
<p>at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)</p>
<p>at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:176)</p>
<p>at $Proxy8.updateName(Unknown Source)</p>
<p>at org.aspectprogrammer.myapp.debug.LostUpdateDetectorTests.testLostUpdateInReadOnly(LostUpdateDetectorTests.java:23)</p>
<p>at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)</p>
<p>at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)</p>
<p>at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)</p>
<p>at java.lang.reflect.Method.invoke(Unknown Source)</p>
<p>at junit.framework.TestCase.runTest(TestCase.java:154)</p>
<p>at junit.framework.TestCase.runBare(TestCase.java:127)</p>
<p>at junit.framework.TestResult$1.protect(TestResult.java:106)</p>
<p>at junit.framework.TestResult.runProtected(TestResult.java:124)</p>
<p>at junit.framework.TestResult.run(TestResult.java:109)</p>
<p>at junit.framework.TestCase.run(TestCase.java:118)</p>
<p>at junit.framework.TestSuite.runTest(TestSuite.java:208)</p>
<p>at junit.framework.TestSuite.run(TestSuite.java:203)</p>
<p>at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)</p>
<p>at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)</p>
<p>at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)</p>
<p>简化“基础结构”需求的实现</p>
<p>当 你越来越习惯于AspectJ和所配套的工具组时，你就可以用AspectJ来实现影响你应用程序所有部分的需求，包括领域模型。作为一个简单的实例，我 将向你介绍如何剖析jpetstore范例的应用程序。让我们首先看一下Profiler方面，然后填入一些外围的细节：</p>
<pre>public aspect Profiler {

  private ProfilingStrategy profiler = new NoProfilingStrategy();

  public void setProfilingStrategy(ProfilingStrategy p) {
    this.profiler = p;
  }

  pointcut profiledOperation() :
    Pointcuts.anyPublicOperation() &amp;&amp;
    SystemArchitecture.inPetStore() &amp;&amp;

    !within(ProfilingStrategy+);

  Object around() : profiledOperation() {
    Object token = this.profiler.start(thisJoinPointStaticPart);
    Object ret = proceed();
    this.profiler.stop(token,thisJoinPointStaticPart);
    return ret;
  }
}</pre>
<p>我们已经将profiledOperation()定义为[the]PetStore()中的anyPublicOperation()了。该方面表现得就像委托给ProfilingStrategy的控制器，我们将利用依赖注入通过Spring对它进行配置。</p>
<pre>&lt;bean id="profiler"
     class="org.springframework.samples.jpetstore.profiling.Profiler"
     factory-method="aspectOf"&gt;

    &lt;property name="profilingStrategy"&gt;
      &lt;ref local="jamonProfilingStrategy"/&gt;
    &lt;/property&gt;
  &lt;/bean&gt;

  &lt;bean id="jamonProfilingStrategy"

     class="org.springframework.samples.jpetstore.profiling.JamonProfilingStrategy"
     init-method="reset"
     destroy-method="report"&gt;
  &lt;/bean&gt;</pre>
<p>注意给方面bean使用了“factory-method”属性，这是配置单例（singleton）AspectJ方面和配置一般的Spring bean之间的唯一区别。我正在用JAMon进行剖析，它提供了一个非常简单的API。</p>
<pre>public class JamonProfilingStrategy implements ProfilingStrategy {

  public Object start(StaticPart jpStaticPart) {
    return MonitorFactory.start(jpStaticPart.toShortString());
  }

  public void stop(Object token, StaticPart jpStaticPart) {
    if (token instanceof Monitor) {
      Monitor mon = (Monitor) token;
      mon.stop();
    }
  }
}</pre>
<p>这就是我们激活适用于整个pet store的剖析所必须做的全部工作。通过将JAMon提供的jsp增加到pet store应用程序，我们就可以在Web浏览器中观看到剖析的输出。以下是我在应用程序周围点击一会之后的屏幕快照：</p>
<p><img src="http://javadou.com/wordpress/wp-content/plugins/wp-o-matic/cache/f2f67_petstore-jamon.jpg" alt="" /></p>
<p>简化领域模型</p>
<p>具有影响你领域模型的多个部分的业务逻辑需求，这也并不罕见。有些明显的实例为：设计模式实现（请见Nick Leseicki关于这个主题的精彩的developerWorks文章　：part 1、part 2），领域对象的依赖注入（例如使用Spring的@Configurable注解），以及业务规则和策略的实现。在采用的这个阶段，你的核心业务逻辑变成了依赖于方面的存在。</p>
<p>你 编写的方面将特定于你的领域。AspectJ和AJDT都利用AspectJ构建，我们在它们的构建中使用了大量特定于领域的方面。举个例子，下面是我在 1.5.1发布的开发期间增加到AspectJ的一个方面：它实现了一项经常被请求的特性，当一个异常被一个空的捕捉块淹没时，用它来发布一个警告。</p>
<pre>public aspect WarnOnSwallowedException {

  pointcut resolvingATryStatement(TryStatement tryStatement, BlockScope inScope)
    : execution(* TryStatement.resolve(..)) &amp;&amp;
      this(tryStatement) &amp;&amp;

      args(inScope,..);

    after(TryStatement tryStatement, BlockScope inScope) returning
      : resolvingATryStatement(tryStatement,inScope) {
      if (tryStatement.catchBlocks != null) {
        for (int i = 0; i &lt; tryStatement.catchBlocks.length; i++) {
   Block catchBlock = tryStatement.catchBlocks[i];
   if (catchBlock.isEmptyBlock() ||
              catchBlock.statements.length == 0) {
     warnOnEmptyCatchBlock(catchBlock,inScope);
   }
        }
      }
    }

    private void warnOnEmptyCatchBlock(Block catchBlock, BlockScope inScope) {
      inScope.problemReporter()
             .swallowedException(catchBlock.sourceStart(),
                                 catchBlock.sourceEnd());
    }
}</pre>
<p>即使在这个实例中，这个方面只在代码库中建议了一个位置，但它除了JDT编译器的功能之外，还通过将这个AspectJ模块化，使得代码更加清楚了，也使得未来的维护人员非常清楚如何实现这项特性。涉及利用方面给领域建模的进一步详情，则是另一篇文章的主题了。</p>
<p>小结</p>
<p>Spring 的目标是提供一种简单而强大的企业应用程序开发方法。利用它对AOP的支持，以及与AspectJ的整合，这种方法延伸到了影响应用程序多个部分的特性的 实现。传统上而言，这些特性的实现都散布到整个应用程序逻辑中，使得它难以添加、去除和维护特性，并且使得应用程序逻辑复杂化。利用方面，Spring让 你能够给这些特性编写整洁、简单且模块化的实现。AOP的采用可以分多个阶段进行：通过利用Spring提供的开箱即用的方面开始，然后可以利用 Spring AOP在Web、服务和数据访问层中添加你自己的@AspectJ方面。AspectJ本身可以被用来提供开发生产力，而不用在AspectJ中引入任何 依赖。更进一步探讨了横贯你应用程序多个层的基础结构需求，可以利用AspectJ方面被简单地实现。最后，你可以用方面来简化你领域模型本身的实现。</p>
<p>关于作者</p>
<p>Adrian Colyer是Interface21的首席科学家，是Eclipse.org的AspectJ项目负责人，以及AspectJ Development Tools（AJDT）项目的创办人。2004年，他被MIT Technology Review投票选为世界前100名年轻的改革者之一，并且经常进行关于Spring、AOP和AspectJ主题的演讲。</p>
<p>关于Interface21</p>
<p>Interface21提供Spring、AOP和AspectJ方面的培训和咨询。至于课程安排或者要安排培训的，请见www.interface21.com。</p>
<p>Adrian Colyer和Spring社区其他成员出席2006年12月7至10日会议的相关内容请见http://www.thespringexperience.com。</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-2-0-aspectj-552/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Spring AOP学习笔记</title>
		<link>http://javadou.com/spring-aop-study-549/</link>
		<comments>http://javadou.com/spring-aop-study-549/#comments</comments>
		<pubDate>Sun, 21 Mar 2010 02:45:43 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[aop]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=549</guid>
		<description><![CDATA[Spring AOP学习笔记 需明确的几个概念： 通知(Advice)：用于告知系统将有哪些新的行为。 切入点(Pointcut):定义了通知应该在应用到那些连接点。 目标对象(Target)：被通知的对象。 代理(Proxy)：将通知应用到目标对象后创... ]]></description>
			<content:encoded><![CDATA[<p>Spring AOP学习笔记 需明确的几个概念： 通知(Advice)：用于告知系统将有哪些新的行为。 切入点(Pointcut):定义了通知应该在应用到那些连接点。 目标对象(Target)：被通知的对象。 代理(Proxy)：将通知应用到目标对象后创建的对象。</p>
<p>需明确的几个概念:</p>
<p>l         通知(Advice)：用于告知系统将有哪些新的行为。</p>
<p>l         切入点(Pointcut):定义了通知应该在应用到那些连接点。</p>
<p>l         目标对象(Target)：被通知的对象。</p>
<p>l         代理(Proxy)：将通知应用到目标对象后创建的对象。</p>
<p>Spring有两种代理创建方式：</p>
<p>1.     如果目标对象实现了一个或多个接口暴露的方法，Spring将使用JDK的java.lang.reflect.Proxy创建代理。这个类让Spring动态产生一个新的类，它实现了所需的接口，织入了通知，并且代理目标的所有请求。（这篇主要介绍这个方式）</p>
<p>2.    如果目标对象没有实现任何接口，Spring使用CGLIB库生成目标对象的子类。在创建这个子类的时候，Spring将通知织入，并且将对目标对象的调用委托给这个子类。</p>
<p>下面以一个实例说明Spring AOP的基本开发方法：</p>
<p>一．创建通知</p>
<p>Spring连接点模型是建立在方法拦截上，这意味着你编写的</p>
<p>Spring通知会在方法调用周围的各个地方织入系统中。</p>
<p><img src="http://javadou.com/wordpress/wp-content/plugins/wp-o-matic/cache/99b57_Image00001.bmp" alt="" /></p>
<p>TestAopServiceAdvice实现了接口MethodBeforeAdvice(前置通知)，并实现它的惟一的方法before，这个类就可以在调用目标对象前被调用。同样的还有AfterReturningAdvice(后置通知)，MethodInterceptor(环绕通知)，异常通知(ThrowsAdvice)，引入通知等。</p>
<p>在这个方法中我们输出了一个字符串TestAopServiceAdvice，用于验证这个方法是否在目标对象前调用了。</p>
<p>注意：我们无法改变before方法中的参数args和target中的值，args中存的是原来要传入目标对象的变量，target即指目标对象。</p>
<p>二．配置Spring XML配置文件</p>
<p>要在Spring中实现AOP，一般情况下需要配置4个bean：</p>
<p>1．    目标对象（target）</p>
<p>2．    通知(advice)</p>
<p>3．    切入点(pointcut)</p>
<p>4．    代理(proxy)</p>
<p><img src="http://javadou.com/wordpress/wp-content/plugins/wp-o-matic/cache/fca30_Image00003.jpg" alt="" /></p>
<p>切入点又分为静态切入点和动态切入点</p>
<p>l         静态切入点的意思是通知总是被执行,也是最常用的一种切入点。</p>
<p>l         动态切入点根据运行时方法的参数值决定通知是否被执行。</p>
<p>在图2中，定义了使用了一个Spring提供的静态切入点</p>
<p>NameMatchMethodPointAdvisor，它保证了当被调用的方法的名字与给出的映射名字相匹配的时候，这个切入点才匹配。</p>
<p>Spring提供的另一个静态切入点为RegexpMethodPointcutAdvisor，让你可以利用正则表达式来定义切入点，正则表达式需要jakarta-oro.jar包的支持。</p>
<p>使用ProxyBeanFactory可以创建一个被通知的类，即代理对象。它的最常用的三个控制行为的属性是：</p>
<p>l         proxyInterfaces：代理应该实现的接口列表。</p>
<p>l         interceptorNames：需要应用到目标对象上的通知Bean的名字。可以是拦截器、Advisor或其他通知类的名字。</p>
<p>注：在用容器的getBean方法时，应该是getBean(代理类的名字)，而不是getBean(目标对象的名字)，否则AOP无法工作。</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-aop-study-549/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>spring aop 初探</title>
		<link>http://javadou.com/spring-aop-550/</link>
		<comments>http://javadou.com/spring-aop-550/#comments</comments>
		<pubDate>Sat, 20 Mar 2010 02:44:57 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[aop]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=550</guid>
		<description><![CDATA[spring aop 初探了解 通知，切点，目标对象，代理对象 1.建一个application工程aopTest 2.导入相应的包（这里用的spring2.5.X） 3.创建目标类LogTarget public class LogTarget { public void login(){ System.out.println("login is run"); } } 4.创建通知... ]]></description>
			<content:encoded><![CDATA[<p>spring aop 初探了解 通知，切点，目标对象，代理对象</p>
<p>1.建一个application工程aopTest</p>
<p>2.导入相应的包（这里用的spring2.5.X）</p>
<p>3.创建目标类LogTarget</p>
<pre>
public class LogTarget {
	public void login(){
		System.out.println("login is run");
	}
}
</pre>
<p>4.创建通知类LogAdvice</p>
<pre>import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class LogAdvice implements MethodBeforeAdvice{

	@Override
	public void before(Method arg0, Object[] arg1, Object arg2)
			throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("befor is run");
	}

}
</pre>
<p>5.配置applicationContext.xml</p>
<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"&gt;
	&lt;!-- 目标对象 --&gt;
	&lt;bean id="logTarget" class="LogTarget"/&gt;
	&lt;!-- 通知 --&gt;
	&lt;bean id="logAdvice" class="LogAdvice"/&gt;
	&lt;!-- 切入点 --&gt;
	&lt;bean id="logPointCutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"&gt;
		&lt;property name="advice"&gt;
			&lt;ref bean="logAdvice"/&gt;
		&lt;/property&gt;
		&lt;property name="pattern"&gt;
			&lt;value&gt;.*login.*&lt;/value&gt;
		&lt;/property&gt;
	&lt;/bean&gt;
	&lt;!-- 代理对象 --&gt;
	&lt;bean id="logProxy" class="org.springframework.aop.framework.ProxyFactoryBean"&gt;
		&lt;property name="target"&gt;
			&lt;ref bean="logTarget"/&gt;
		&lt;/property&gt;
		&lt;property name="interceptorNames"&gt;
			&lt;list&gt;
				&lt;value&gt;logPointCutAdvisor&lt;/value&gt;
			&lt;/list&gt;
		&lt;/property&gt;
	&lt;/bean&gt;
&lt;/beans&gt;
</pre>
<p>6.编写测试类TestMain</p>
<pre>import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class TestMain {
	public static void main(String[] args) {
		ApplicationContext ctx = new FileSystemXmlApplicationContext(
				"src/applicationContext.xml");
		LogTarget logtarget=(LogTarget)ctx.getBean("logProxy");
		logtarget.login();
	}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-aop-550/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Spring @AspectJ 实现AOP 入门例子</title>
		<link>http://javadou.com/spring-aspectj-aop-demo-551/</link>
		<comments>http://javadou.com/spring-aspectj-aop-demo-551/#comments</comments>
		<pubDate>Fri, 19 Mar 2010 02:43:51 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[aop]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=551</guid>
		<description><![CDATA[Spring AspectJ 实现AOP 入门例子 OP的作用这里就不再作说明了，下面开始讲解一个很简单的入门级例子。 引用一个猴子偷桃，守护者守护果园抓住猴子的小情节。 1、猴子偷桃类（普通类）： package com.samter.common; /** * ... ]]></description>
			<content:encoded><![CDATA[<p>Spring @AspectJ 实现AOP 入门例子<br />
OP的作用这里就不再作说明了，下面开始讲解一个很简单的入门级例子。</p>
<p>引用一个猴子偷桃，守护者守护果园抓住猴子的小情节。</p>
<p>1、猴子偷桃类（普通类）：</p>
<pre>package com.samter.common;   

/**
* 猴子
* @author Administrator
*
*/
public class Monkey {   

    public void stealPeaches(String name){
         System.out.println("【猴子】"+name+"正在偷桃...");
     }
}</pre>
<p>2、守护者类（声明为Aspect）：</p>
<pre>package com.samter.aspect;   

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;   

/**
* 桃园守护者
* @author Administrator
*
*/  

@Aspect
public class Guardian {   

    @Pointcut("execution(* com.samter.common.Monkey.stealPeaches(..))")
    public void foundMonkey(){}   

    @Before(value="foundMonkey()")
    public void foundBefore(){
         System.out.println("【守护者】发现猴子正在进入果园...");
     }   

    @AfterReturning("foundMonkey() &amp;&amp; args(name,..)")
    public void foundAfter(String name){
         System.out.println("【守护者】抓住了猴子,守护者审问出了猴子的名字叫“"+name+"”...");
     }   

}</pre>
<p>3、XML配置文件：</p>
<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
&gt;   

     &lt;!-- 定义Aspect --&gt;
     &lt;bean id="guardian" class="com.samter.aspect.Guardian" /&gt;   

     &lt;!-- 定义Common --&gt;
     &lt;bean id="monkey" class="com.samter.common.Monkey" /&gt;   

     &lt;!-- 启动AspectJ支持 --&gt;
     &lt;aop:aspectj-autoproxy /&gt;   

&lt;/beans&gt;</pre>
<p>4、测试类：</p>
<pre>package com.samter.common;   

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;   

public class Main {   

    public static void main(String[] args) {
         ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
         Monkey monkey = (Monkey) context.getBean("monkey");
        try {
             monkey.stealPeaches("孙大圣的大徒弟");
         }
        catch(Exception e) {}
     }   

}</pre>
<p>5、控制台输出：</p>
<p>Java代码</p>
<p>【守护者】发现猴子正在进入果园&#8230;</p>
<p>【猴子】孙大圣的大徒弟正在偷桃&#8230;</p>
<p>【守护者】抓住了猴子,守护者审问出了猴子的名字叫“孙大圣的大徒弟”&#8230;</p>
<p>解说：1写了一个猴子正在偷桃的方法。</p>
<p>2写了一个标志为@Aspect的类，它是守护者。它会在猴子偷桃之前发现猴子，并在猴子偷桃之后抓住猴子。</p>
<p>原理：A、@Aspect的声明表示这是一个切面类。</p>
<p>B、@Pointcut使用这个方法可以将com.samter.common.Monkey.stealPeaches(..)方法声明为poincut即切入点。作用,在stealPeaches方法被调用的时候执行2的foundMonkey方法。其中execution是匹配方法执行的切入点，也就是spring最常用的切入点定义方式。</p>
<p>C、@Before(value=&#8221;foundMonkey()&#8221;)：@Before声明为在切入点方法执行之前执行，而后面没有直接声明切入点，而是value=&#8221;foundMonkey()&#8221;，是因为如果@afterReturning等都有所改动的时候都必须全部改动，所以统一用Pointcut的foundMonkey代替，这样子有改动的时候仅需改动一个地方。其他@AfterReturning类同。</p>
<p>3是xml配置文件，里面有具体的注释。</p>
<p>特别说明：Guardian类里面的@Pointcut(&#8220;execution(* com.samter.common.Monkey.stealPeaches(..))&#8221;)，如果stealPeaches有参数则..表示所有参数，@AfterReturning(&#8220;foundMonkey() &amp;&amp; args(name,..)&#8221;)的&amp;&amp; args(name,..)可以获取切入点方法stealPeaches的参数。</p>
<p>总结：这里列举了一个简单的例子，但是不难引申到应用中，当你写一个登陆系统的时候，你或许要记录谁成功登陆了系统，谁登陆系统密码错误等等的信息，这样子你用切面是再合适不过的了，总之当你的事务逻辑都设计到日志、安全检查、事务管理等等共同的内容的时候，用切面是要比你没有一个事务逻辑类都有相关代码或者相关引用好得多。</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-aspectj-aop-demo-551/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用spring定时任务时间格式cronExpression设置</title>
		<link>http://javadou.com/spring-quartz-cronexpression-491/</link>
		<comments>http://javadou.com/spring-quartz-cronexpression-491/#comments</comments>
		<pubDate>Sat, 09 Jan 2010 07:09:37 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[quartz]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/?p=491</guid>
		<description><![CDATA[最近做的项目大量的使用了spring的定时功能 所以有必要整理一下相关资料给大家 org.springframework.scheduling.quartz.CronTriggerBean允许你更精确地控制任务的运行时间，只需要设置其cronExpression属性。 一个cronExpression表达式... ]]></description>
			<content:encoded><![CDATA[<p>      最近做的项目大量的使用了spring的定时功能 所以有必要整理一下相关资料给大家<br />
org.springframework.scheduling.quartz.CronTriggerBean允许你更精确地控制任务的运行时间，只需要设置其cronExpression属性。<br />
    一个cronExpression表达式有至少6个（也可能是7个）由空格分隔的时间元素。从左至右，这些元素的定义如下：<br />
1．秒（0–59）<br />
2．分钟（0–59）<br />
3．小时（0–23）<br />
4．月份中的日期（1–31）<br />
5．月份（1–12或JAN–DEC）<br />
6．星期中的日期（1–7或SUN–SAT）<br />
7．年份（1970–2099）<br />
0 0 10,14,16 * * ?       每天上午10点,下午2点和下午4点<br />
0 0,15,30,45 * 1-10 * ?  每月前10天每隔15分钟<br />
30 0 0 1 1 ? 2012        在2012年1月1日午夜过30秒时<br />
0 0 8-5 ? * MON-FRI      每个工作日的工作时间</p>
<p>各个时间可用值如下：<br />
秒 0-59 , &#8211; * /<br />
分 0-59 , &#8211; * /<br />
小时 0-23 , &#8211; * /<br />
日 1-31 , &#8211; * ? / L W C<br />
月 1-12 or JAN-DEC , &#8211; * /<br />
周几 1-7 or SUN-SAT , &#8211; * ? / L C #<br />
年 (可选字段) empty, 1970-2099 , &#8211; * /</p>
<p>可用值详细分析如下：</p>
<p>“*”——字符可以用于所有字段，在“分”字段中设为&#8221;*&#8221;表示&#8221;每一分钟&#8221;的含义。</p>
<p>“?”——字符可以用在“日”和“周几”字段. 它用来指定 &#8216;不明确的值&#8217;. 这在你需要指定这两个字段中的某一个值而不是另外一个的时候会被用到。在后面的例子中可以看到其含义。</p>
<p>“-”——字符被用来指定一个值的范围，比如在“小时”字段中设为&#8221;10-12&#8243;表示&#8221;10点到12点&#8221;。</p>
<p>“,”——字符指定数个值。比如在“周几”字段中设为&#8221;MON,WED,FRI&#8221;表示&#8221;the days Monday, Wednesday, and Friday&#8221;。</p>
<p>“/”——字符用来指定一个值的的增加幅度. 比如在“秒”字段中设置为&#8221;0/15&#8243;表示&#8221;第0, 15, 30, 和 45秒&#8221;。而 &#8220;5/15&#8243;则表示&#8221;第5, 20, 35, 和 50&#8243;. 在&#8217;/'前加&#8221;*&#8221;字符相当于指定从0秒开始. 每个字段都有一系列可以开始或结束的数值。对于“秒”和“分”字段来说，其数值范围为0到59，对于“小时”字段来说其为0到23, 对于“日”字段来说为0到31, 而对于“月”字段来说为1到12。&#8221;/&#8221;字段仅仅只是帮助你在允许的数值范围内从开始&#8221;第n&#8221;的值。</p>
<p>“L”——字符可用在“日”和“周几”这两个字段。它是&#8221;last&#8221;的缩写, 但是在这两个字段中有不同的含义。例如,“日”字段中的&#8221;L&#8221;表示&#8221;一个月中的最后一天&#8221; —— 对于一月就是31号对于二月来说就是28号（非闰年）。而在“周几”字段中, 它简单的表示&#8221;7&#8243; or &#8220;SAT&#8221;，但是如果在“周几”字段中使用时跟在某个数字之后, 它表示&#8221;该月最后一个星期×&#8221; —— 比如&#8221;6L&#8221;表示&#8221;该月最后一个周五&#8221;。当使用&#8217;L'选项时,指定确定的列表或者范围非常重要，否则你会被结果搞糊涂的。</p>
<p>“W”——可用于“日”字段。用来指定历给定日期最近的工作日(周一到周五) 。比如你将“日”字段设为&#8221;15W&#8221;，意为: &#8220;离该月15号最近的工作日&#8221;。因此如果15号为周六，触发器会在14号即周五调用。如果15号为周日, 触发器会在16号也就是周一触发。如果15号为周二,那么当天就会触发。然而如果你将“日”字段设为&#8221;1W&#8221;, 而一号又是周六, 触发器会于下周一也就是当月的3号触发,因为它不会越过当月的值的范围边界。&#8217;W'字符只能用于“日”字段的值为单独的一天而不是一系列值的时候。</p>
<p>“L”和“W”可以组合用于“日”字段表示为&#8217;LW&#8217;，意为&#8221;该月最后一个工作日&#8221;。</p>
<p>“#”—— 字符可用于“周几”字段。该字符表示“该月第几个周×”，比如&#8221;6#3&#8243;表示该月第三个周五( 6表示周五而&#8221;#3&#8243;该月第三个)。再比如: &#8220;2#1&#8243; = 表示该月第一个周一而 &#8220;4#5&#8243; = 该月第五个周三。注意如果你指定&#8221;#5&#8243;该月没有第五个“周×”，该月是不会触发的。</p>
<p>“C”—— 字符可用于“日”和“周几”字段，它是&#8221;calendar&#8221;的缩写。 它表示为基于相关的日历所计算出的值（如果有的话）。如果没有关联的日历, 那它等同于包含全部日历。“日”字段值为&#8221;5C&#8221;表示&#8221;日历中的第一天或者5号以后&#8221;，“周几”字段值为&#8221;1C&#8221;则表示&#8221;日历中的第一天或者周日以后&#8221;。</p>
<p>对于“月份”字段和“周几”字段来说合法的字符都不是大小写敏感的。</p>
<p>一些例子：<br />
&#8220;0 0 12 * * ?&#8221; 每天中午十二点触发<br />
&#8220;0 15 10 ? * *&#8221; 每天早上10：15触发<br />
&#8220;0 15 10 * * ?&#8221; 每天早上10：15触发<br />
&#8220;0 15 10 * * ? *&#8221; 每天早上10：15触发<br />
&#8220;0 15 10 * * ? 2005&#8243; 2005年的每天早上10：15触发<br />
&#8220;0 * 14 * * ?&#8221; 每天从下午2点开始到2点59分每分钟一次触发<br />
&#8220;0 0/5 14 * * ?&#8221; 每天从下午2点开始到2：55分结束每5分钟一次触发<br />
&#8220;0 0/5 14,18 * * ?&#8221; 每天的下午2点至2：55和6点至6点55分两个时间段内每5分钟一次触发<br />
&#8220;0 0-5 14 * * ?&#8221; 每天14:00至14:05每分钟一次触发<br />
&#8220;0 10,44 14 ? 3 WED&#8221; 三月的每周三的14：10和14：44触发<br />
&#8220;0 15 10 ? * MON-FRI&#8221; 每个周一、周二、周三、周四、周五的10：15触发<br />
&#8220;0 15 10 15 * ?&#8221; 每月15号的10：15触发<br />
&#8220;0 15 10 L * ?&#8221; 每月的最后一天的10：15触发<br />
&#8220;0 15 10 ? * 6L&#8221; 每月最后一个周五的10：15</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-quartz-cronexpression-491/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>搜索特定类在当前ClassPath中</title>
		<link>http://javadou.com/spring-classpath-search-one-class-246/</link>
		<comments>http://javadou.com/spring-classpath-search-one-class-246/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 19:16:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Java核心类]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[classpath]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-classpath-search-one-class-246/</guid>
		<description><![CDATA[Spring 2.5提供了自动在当前ClassPath搜索被标注有特定注解的类，这个特性非常有用，跟踪了一下源码，发现其实核心代码就是利用ClassLoader的方法： 


public Enumeration getResources(String name)

于是自己动手，也写了一个... ]]></description>
			<content:encoded><![CDATA[<p>Spring 2.5提供了自动在当前ClassPath搜索被标注有特定注解的类，这个特性非常有用，跟踪了一下源码，发现其实核心代码就是利用ClassLoader的方法：    </p>
<p><strong>public Enumeration&lt;URL&gt; getResources(String name)</strong></p>
<p>于是自己动手，也写了一个能在ClassPath下搜索特定类的Scanner：    </p>
<pre class="java">package com.<a href="http://javadou.com">javadou</a>.util;


import java.io.File;
  import java.io.IOException;

import java.net.URL;

import java.util.ArrayList;

import java.util.Enumeration;

import java.util.List;

import java.util.jar.JarEntry;

import java.util.jar.JarFile;

public class ClassPathScanner {

&#160;&#160;&#160; private static final String PROTOCOL_FILE = &quot;file&quot;;
  &#160;&#160;&#160; private static final String PROTOCOL_JAR = &quot;jar&quot;;

&#160;&#160;&#160; private static final String PREFIX_FILE = &quot;file:&quot;;

&#160;&#160;&#160; private static final String JAR_URL_SEPERATOR = &quot;!/&quot;;
  &#160;&#160;&#160; private static final String CLASS_FILE = &quot;.class&quot;;

&#160;&#160;&#160; private final String packageName;
  &#160;&#160;&#160; private final ClassFilter filter;

&#160;&#160;&#160; public ClassPathScanner(String packageName) {
  &#160;&#160;&#160;&#160;&#160;&#160;&#160; this(packageName, null);

&#160;&#160;&#160; }

&#160;&#160;&#160; public ClassPathScanner(String packageName, ClassFilter filter) {
  &#160;&#160;&#160;&#160;&#160;&#160;&#160; this.packageName = packageName;

&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.filter = filter;

&#160;&#160;&#160; }

public List&lt;Class&lt;?&gt;&gt; scan() {
  &#160;&#160;&#160;&#160;&#160;&#160;&#160; List&lt;Class&lt;?&gt;&gt; list = new ArrayList&lt;Class&lt;?&gt;&gt;();

&#160;&#160;&#160;&#160;&#160;&#160;&#160; Enumeration&lt;URL&gt; en = null;

&#160;&#160;&#160;&#160;&#160;&#160;&#160; try {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; en = getClass().getClassLoader().getResources(dotToPath(packageName));

&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160; catch(IOException e) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; e.printStackTrace();

&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160; while (en.hasMoreElements()) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; URL url = en.nextElement();

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (PROTOCOL_FILE.equals(url.getProtocol())) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; File root = new File(url.getFile());

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; findInDirectory(list, root, root, packageName);

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; else if (PROTOCOL_JAR.equals(url.getProtocol())) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; findInJar(list, getJarFile(url), packageName);

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160; return list;

&#160;&#160;&#160; }

&#160;&#160;&#160; public File getJarFile(URL url) {
  &#160;&#160;&#160;&#160;&#160;&#160;&#160; String file = url.getFile();

&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (file.startsWith(PREFIX_FILE))

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; file = file.substring(PREFIX_FILE.length());

&#160;&#160;&#160;&#160;&#160;&#160;&#160; int end = file.indexOf(JAR_URL_SEPERATOR);

&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (end!=(-1))

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; file = file.substring(0, end);

&#160;&#160;&#160;&#160;&#160;&#160;&#160; return new File(file);

&#160;&#160;&#160; }

&#160;&#160;&#160; void findInJar(List&lt;Class&lt;?&gt;&gt; results, File file, String packageName) {
  &#160;&#160;&#160;&#160;&#160;&#160;&#160; JarFile jarFile = null;

&#160;&#160;&#160;&#160;&#160;&#160;&#160; String packagePath = dotToPath(packageName) + &quot;/&quot;;

&#160;&#160;&#160;&#160;&#160;&#160;&#160; try {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; jarFile = new JarFile(file);

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Enumeration&lt;JarEntry&gt; en = jarFile.entries();

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; while (en.hasMoreElements()) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; JarEntry je = en.nextElement();

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String name = je.getName();

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (name.startsWith(packagePath) &amp;&amp; name.endsWith(CLASS_FILE)) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String className = name.substring(0, name.length() - CLASS_FILE.length());

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; add(results, pathToDot(className));

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160; catch(IOException e) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; e.printStackTrace();

&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160; finally {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (jarFile!=null) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; try {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; jarFile.close();

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; catch(IOException e) {}

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160; }

&#160;&#160;&#160; void findInDirectory(List&lt;Class&lt;?&gt;&gt; results, File rootDir, File dir, String packageName) {
  &#160;&#160;&#160;&#160;&#160;&#160;&#160; File[] files = dir.listFiles();

&#160;&#160;&#160;&#160;&#160;&#160;&#160; String rootPath = rootDir.getPath();

&#160;&#160;&#160;&#160;&#160;&#160;&#160; for (File file : files) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (file.isFile()) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String classFileName = file.getPath();

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (classFileName.endsWith(CLASS_FILE)) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String className = classFileName.substring(rootPath.length() - packageName.length(), classFileName.length() - CLASS_FILE.length());

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; add(results, pathToDot(className));

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; else if (file.isDirectory()) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; findInDirectory(results, rootDir, file, packageName);

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160; }

&#160;&#160;&#160; void add(List&lt;Class&lt;?&gt;&gt; results, String className) {
  &#160;&#160;&#160;&#160;&#160;&#160;&#160; Class&lt;?&gt; clazz = null;

&#160;&#160;&#160;&#160;&#160;&#160;&#160; try {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; clazz = Class.forName(className);

&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160; catch(ClassNotFoundException e) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return;

&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (filter==null || filter.accept(clazz))

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; results.add(clazz);

&#160;&#160;&#160; }

&#160;&#160;&#160; String dotToPath(String s) {
  &#160;&#160;&#160;&#160;&#160;&#160;&#160; return s.replace('.', '/');

&#160;&#160;&#160; }

&#160;&#160;&#160; String pathToDot(String s) {
  &#160;&#160;&#160;&#160;&#160;&#160;&#160; return s.replace('/', '.').replace('\\', '.');

&#160;&#160;&#160; }

}

public interface ClassFilter {

&#160;&#160;&#160; boolean accept(Class&lt;?&gt; clazz);

}

用法：

&#160;&#160;&#160; public static void main(String[] args) {
  &#160;&#160;&#160;&#160;&#160;&#160;&#160; List&lt;Class&lt;?&gt;&gt; list = new ClassPathScanner(

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &quot;org.springframework.core.io&quot;,

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; new ClassFilter() {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; public boolean accept(Class&lt;?&gt; clazz) {
  &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return clazz.isInterface();

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160;&#160;&#160;&#160;&#160; ).scan();

&#160;&#160;&#160;&#160;&#160;&#160;&#160; for (Class&lt;?&gt; clazz : list) {

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println(clazz);

&#160;&#160;&#160;&#160;&#160;&#160;&#160; }

&#160;&#160;&#160; }
</pre>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-classpath-search-one-class-246/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring 发布时所需的最小包依赖</title>
		<link>http://javadou.com/spring-min-jar-244/</link>
		<comments>http://javadou.com/spring-min-jar-244/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 06:49:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-min-jar-244/</guid>
		<description><![CDATA[Copy the following files into the library directory: - spring.jar - commons-logging.jar - servlet-api.jar web.xml &60;?xml version=&34;1.0&34; encoding=&34;ISO-8859-1&34;?&62; &60;!DOCTYPE web-app PUBLIC &34;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&34; &34;htt... ]]></description>
			<content:encoded><![CDATA[<p>Copy the following files into the library directory:   <br />- spring.jar    <br />- commons-logging.jar    <br />- servlet-api.jar</p>
<p><strong>web.xml</strong></p>
<p>&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;</p>
<p>&lt;!DOCTYPE web-app PUBLIC   <br /> &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot;    <br /> &quot;<a href="http://java.sun.com/dtd/web-app_2_3.dtd">http://java.sun.com/dtd/web-app_2_3.dtd</a>&quot;&gt;</p>
<p>&lt;!&#8211;   <br />&#160; &#8211; Web app deployment descriptor that just loads an &quot;example&quot; DispatcherServlet    <br />&#160; &#8211; with a specific context.    <br />&#160; &#8211;    <br />&#160; &#8211; Depends on the following libraries in WEB-INF/lib:    <br />&#160; &#8211; * spring.jar    <br />&#160; &#8211; * commons-logging.jar    <br />&#160; &#8211;&gt;    <br />&lt;web-app&gt;</p>
<p>&#160; &lt;!&#8211;   <br />&#160;&#160;&#160; &#8211; Servlet that dispatches request to registered handlers (Controller implementations).    <br />&#160;&#160;&#160; &#8211; Has its own application context, by default defined in &quot;{servlet-name}-servlet.xml&quot;,    <br />&#160;&#160;&#160; &#8211; i.e. &quot;example-servlet.xml&quot;.    <br />&#160;&#160;&#160; &#8211;    <br />&#160;&#160;&#160; &#8211; A web app can contain any number of such servlets.    <br />&#160;&#160;&#160; &#8211; Note that this web app does not have a shared root application context,    <br />&#160;&#160;&#160; &#8211; therefore the DispatcherServlet contexts do not have a common parent.    <br />&#160;&#160;&#160; &#8211;&gt;    <br /> &lt;servlet&gt;    <br />&#160; &lt;servlet-name&gt;example&lt;/servlet-name&gt;    <br />&#160; &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;    <br />&#160; &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;    <br />&#160; &lt;/servlet&gt;</p>
<p>&#160; &lt;!&#8211;   <br />&#160;&#160;&#160; &#8211; Maps the example dispatcher to /example/*. All handler mappings in    <br />&#160;&#160;&#160; &#8211; example-servlet.xml will by default be applied to this subpath.    <br />&#160;&#160;&#160; &#8211; If a mapping isn&#8217;t a /* subpath, the handler mappings are considered    <br />&#160;&#160;&#160; &#8211; relative to the web app root.    <br />&#160;&#160;&#160; &#8211;    <br />&#160;&#160;&#160; &#8211; A single dispatcher could get mapped to multiple paths, like any servlet.    <br />&#160;&#160;&#160; &#8211;&gt;    <br /> &lt;servlet-mapping&gt;    <br />&#160;&#160;&#160; &lt;servlet-name&gt;example&lt;/servlet-name&gt;    <br />&#160;&#160;&#160; &lt;url-pattern&gt;/example/*&lt;/url-pattern&gt;    <br />&#160; &lt;/servlet-mapping&gt;    <br />&#160; &lt;welcome-file-list&gt;    <br />&#160; &lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;    <br /> &lt;/welcome-file-list&gt;</p>
<p>&lt;/web-app&gt;</p>
<p><strong>example-servlet.xml</strong></p>
<p><strong></strong></p>
<p>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;   <br />&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;<a href="http://www.springframework.org/dtd/spring-beans.dtd">http://www.springframework.org/dtd/spring-beans.dtd</a>&quot;&gt;</p>
<p>&lt;!&#8211;   <br />&#160; &#8211; Application context definition for &quot;example&quot; DispatcherServlet.    <br />&#160; &#8211;&gt;    <br />&lt;beans&gt;</p>
<p> &lt;!&#8211;   <br />&#160;&#160; &#8211; Due to the dispatcher mapping in web.xml and the default BeanNameUrlHandlerMapping    <br />&#160;&#160; &#8211; in this context, &quot;<a href="http://localhost/example/test">http://localhost/example/test</a>&quot; will trigger this controller.    <br />&#160;&#160; &#8211;    <br />&#160;&#160; &#8211; Due to the default InternalResourceViewResolver, returned view names get treated    <br />&#160;&#160; &#8211; as internal resources, e.g. JSPs: &quot;/test.jsp&quot; or &quot;/WEB-INF/jsp/test.jsp&quot; will    <br />&#160;&#160; &#8211; render the respective file. So with the default resolver, controllers have to    <br />&#160;&#160; &#8211; specify the whole resource path as view name (see below for an alternative).    <br />&#160;&#160; &#8211;    <br />&#160;&#160; &#8211; HandlerMapping and ViewResolver are simple interfaces: Choose one of Spring&#8217;s    <br />&#160;&#160; &#8211; provided implementations, or write your own one.    <br />&#160;&#160; &#8211;    <br />&#160;&#160; &#8211; A very simple Controller implementation could look as follows:    <br />&#160;&#160; &#8211;    <br />&#160;&#160; -&#160;&#160; public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {    <br />&#160;&#160; -&#160;&#160;&#160;&#160; return new ModelAndView(&quot;/test.jsp&quot;);    <br />&#160;&#160; -&#160;&#160; }    <br />&#160;&#160; &#8211;    <br />&#160;&#160; &#8211; Or for writing the response directly:    <br />&#160;&#160; &#8211;    <br />&#160;&#160; -&#160;&#160; public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {    <br />&#160;&#160; -&#160;&#160;&#160;&#160; response.getWriter().write(&quot;This is a test&quot;);    <br />&#160;&#160; -&#160;&#160;&#160;&#160; return null;    <br />&#160;&#160; -&#160;&#160; }    <br />&#160;&#160;&#160; &#8211;&gt;    <br /> &lt;bean name=&quot;/test&quot; class=&quot;example.ExampleController&quot;/&gt;</p>
<p> &lt;!&#8211;   <br />&#160;&#160; &#8211; Optional: Explicit InternalResourceViewResolver definition,    <br />&#160;&#160; &#8211; specifying view class, name prefix, and name suffix.    <br />&#160;&#160; &#8211;    <br />&#160;&#160; &#8211; Specifying the JstlView class instead of the default InternalResourceView    <br />&#160;&#160; &#8211; exports Spring&#8217;s message source and the current user locale as standard    <br />&#160;&#160; &#8211; JSTL attributes, to be leveraged by JSTL fmt tags.    <br />&#160;&#160; &#8211;    <br />&#160;&#160; &#8211; A prefix/suffix combination allows for symbolic view names to be returned    <br />&#160;&#160; &#8211; by controllers, still getting straightly mapped to internal resources.    <br />&#160;&#160; &#8211; Example: view name &quot;test&quot; -&gt; resource &quot;/WEB-INF/jsp/test.jsp&quot;.    <br />&#160;&#160; &#8211;    <br />&#160;&#160; &#8211; For more sophisticated mappings, consider ResourceBundleViewResolver    <br />&#160;&#160; &#8211; (see &quot;webapp-typical&quot; skeleton) or XmlViewResolver.    <br />&#160;&#160; &#8211;&gt;    <br /> &lt;!&#8211;    <br /> &lt;bean id=&quot;viewResolver&quot; class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;&gt;    <br />&#160; &lt;property name=&quot;viewClass&quot;&gt;&lt;value&gt;org.springframework.web.servlet.view.JstlView&lt;/value&gt;&lt;/property&gt;    <br />&#160; &lt;property name=&quot;prefix&quot;&gt;&lt;value&gt;/WEB-INF/jsp/&lt;/value&gt;&lt;/property&gt;    <br />&#160; &lt;property name=&quot;suffix&quot;&gt;&lt;value&gt;.jsp&lt;/value&gt;&lt;/property&gt;    <br /> &lt;/bean&gt;    <br /> &#8211;&gt;</p>
<p>&lt;/beans&gt;</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-min-jar-244/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring BeanFactory 简单模仿帮助大家理解</title>
		<link>http://javadou.com/spring-beanfactory-lijie-243/</link>
		<comments>http://javadou.com/spring-beanfactory-lijie-243/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 05:48:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[beanfactory]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-beanfactory-lijie-243/</guid>
		<description><![CDATA[Spring 是什么, 就是个大 Map. import java.io.InputStream; import java.util.Enumeration; import java.util.Hashtable; import java.util.Map; import java.util.Properties; public class BeanFactory { private static Map&60;String, Object&62; objectPool = new Hashtable&60;String, Ob... ]]></description>
			<content:encoded><![CDATA[<p>Spring 是什么, 就是个大 Map.</p>
<pre class="java">import java.io.InputStream;

import java.util.Enumeration;

import java.util.Hashtable;

import java.util.Map;

import java.util.Properties;

public class BeanFactory {

private static Map&lt;String, Object&gt; objectPool = new Hashtable&lt;String, Object&gt;();

static {

Properties config = new Properties();

InputStream in = BeanFactory.class

.getResourceAsStream(&quot;beans-config.properties&quot;);

if (in == null) {

throw new ExceptionInInitializerError(

&quot;no file:beans-config found error!&quot;);

}

try {

config.load(in);

in.close();

Enumeration ids = config.propertyNames();

while (ids.hasMoreElements()) {

String id = (String) ids.nextElement();

String className = config.getProperty(id);

Object instance = Class.forName(className).newInstance();

objectPool.put(id, instance);

}

} catch (Exception e) {

e.printStackTrace();

throw new ExceptionInInitializerError(&quot;failed to init bean pools!&quot;);

}

}

public static Object getBean(String id) {

return objectPool.get(id);

}

}</pre>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-beanfactory-lijie-243/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring + Eclipse 开发入门:转载</title>
		<link>http://javadou.com/spring-eclipse-242/</link>
		<comments>http://javadou.com/spring-eclipse-242/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 03:46:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[MyEclipse]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[myeclipse]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-eclipse-242/</guid>
		<description><![CDATA[Spring是一个非常优秀的轻量级框架，通过Spring的IoC容器，我们的关注点便放到了需要实现的业务逻辑上。对AOP的支持则能让我们动态增强业务方法。编写普通的业务逻辑Bean是非常容易而且易于测试的，因为它能脱离J... ]]></description>
			<content:encoded><![CDATA[<p>Spring是一个非常优秀的轻量级框架，通过Spring的IoC容器，我们的关注点便放到了需要实现的业务逻辑上。对AOP的支持则能让我们动态增强业务方法。编写普通的业务逻辑Bean是非常容易而且易于测试的，因为它能脱离J2EE容器（如Servlet，JSP环境）单独进行单元测试。最后的一步便是在Spring框架中将这些业务Bean以XML配置文件的方式组织起来，它们就按照我们预定的目标正常工作了！非常容易！</p>
<p>本文将给出一个基本的Spring入门示例，并演示如何使用Spring的AOP将复杂的业务逻辑分离到每个方面中。</p>
<p>1．开发环境配置    <br />2．编写Bean接口及其实现     <br />3．在Spring中配置Bean并获得Bean的实例     <br />4．编写Advisor以增强ServiceBean     <br />5．总结</p>
<h5>1．开发环境配置</h5>
<p>首先，需要正确配置Java环境。推荐安装JDK1.4.2，并正确配置环境变量：</p>
<p>JAVA_HOME=&lt;JDK安装目录&gt;    <br />CLASSPATH=.     <br />Path=%JAVA_HOME%\bin;……</p>
<p>我们将使用免费的Eclipse 3.1作为IDE。新建一个Java Project，将Spring的发布包spring.jar以及commons-logging-1.0.4.jar复制到Project目录下，并在 Project &gt; Properties中配置好Java Build Path：</p>
<p><img height="430" alt="" src="http://www.javaeedev.com/upload/5/6/ff80808112ccf1bc0112d1f018470041.jpg" width="653" /></p>
<h5>2．编写Bean接口及其实现</h5>
<p>我们实现一个管理用户的业务Bean。首先定义一个ServiceBean接口，声明一些业务方法：</p>
<pre>/** * Copyright_2006, Liao Xuefeng * Created on 2006-3-9 * For more information, please visit: <a href="http://www.javaeedevee.com/"><u>http://www.javaeedev.com</u></a> */package com.crackj2ee.example.spring;</pre>
<pre>/** * Interface of service facade. *  * @author Xuefeng */public interface ServiceBean {&#160;&#160;&#160; void addUser(String username, String password);&#160;&#160;&#160; void deleteUser(String username);&#160;&#160;&#160; boolean findUser(String username);&#160;&#160;&#160; String getPassword(String username);}</pre>
<p>然后在MyServiceBean中实现接口：</p>
<pre>/** * Copyright_2006, Liao Xuefeng * Created on 2006-3-9 */package com.crackj2ee.example.spring;</pre>
<pre>import java.util.*;</pre>
<pre>public class MyServiceBean implements ServiceBean {</pre>
<pre>&#160;&#160;&#160; private String dir;&#160;&#160;&#160; private Map map = new HashMap();</pre>
<pre>&#160;&#160;&#160; public void setUserDir(String dir) {&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.dir = dir;&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println(&quot;Set user dir to: &quot; + dir);&#160;&#160;&#160; }</pre>
<pre>&#160;&#160;&#160; public void addUser(String username, String password) {&#160;&#160;&#160;&#160;&#160;&#160;&#160; if(!map.containsKey(username))&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; map.put(username, password);&#160;&#160;&#160;&#160;&#160;&#160;&#160; else&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new RuntimeException(&quot;User already exist.&quot;);&#160;&#160;&#160; }</pre>
<pre>&#160;&#160;&#160; public void deleteUser(String username) {&#160;&#160;&#160;&#160;&#160;&#160;&#160; if(map.remove(username)==null)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new RuntimeException(&quot;User not exist.&quot;);&#160;&#160;&#160; }</pre>
<pre>&#160;&#160;&#160; public boolean findUser(String username) {&#160;&#160;&#160;&#160;&#160;&#160;&#160; return map.containsKey(username);&#160;&#160;&#160; }</pre>
<pre>&#160;&#160;&#160; public String getPassword(String username) {&#160;&#160;&#160;&#160;&#160;&#160;&#160; return (String)map.get(username);&#160;&#160;&#160; }}</pre>
<p>为了简化逻辑，我们使用一个Map保存用户名和口令。</p>
<p>现在，我们已经有了一个业务Bean。要测试它非常容易，因为到目前为止，我们还没有涉及到Spring容器，也没有涉及到任何Web容器（假定这是一个Web应用程序关于用户管理的业务Bean）。完全可以直接进行Unit测试，或者，简单地写个main方法测试：</p>
<pre>/** * Copyright_2006, Liao Xuefeng * Created on 2006-3-9 */package com.crackj2ee.example.spring;</pre>
<pre>public class Main {</pre>
<pre>&#160;&#160;&#160; public static void main(String[] args) throws Exception {&#160;&#160;&#160;&#160;&#160;&#160;&#160; ServiceBean service = new MyServiceBean();&#160;&#160;&#160;&#160;&#160;&#160;&#160; service.addUser(&quot;bill&quot;, &quot;hello&quot;);&#160;&#160;&#160;&#160;&#160;&#160;&#160; service.addUser(&quot;tom&quot;, &quot;goodbye&quot;);&#160;&#160;&#160;&#160;&#160;&#160;&#160; service.addUser(&quot;tracy&quot;, &quot;morning&quot;);&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println(&quot;tom's password is: &quot; + service.getPassword(&quot;tom&quot;));&#160;&#160;&#160;&#160;&#160;&#160;&#160; if(service.findUser(&quot;tom&quot;)) {&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; service.deleteUser(&quot;tom&quot;);&#160;&#160;&#160;&#160;&#160;&#160;&#160; }&#160;&#160;&#160; }}</pre>
<p>执行结果：</p>
<p><img height="184" alt="" src="http://www.javaeedev.com/upload/5/2/ff80808112ccf1bc0112d1f1b3b50042.jpg" width="566" /></p>
<h5>3．在Spring中配置Bean并获得Bean的实例</h5>
<p>我们已经在一个main方法中实现了业务，不过，将对象的生命周期交给容器管理是更好的办法，我们就不必为初始化对象和销毁对象进行硬编码，从而获得更大的灵活性和可测试性。</p>
<p>想要把ServiceBean交给Spring来管理，我们需要一个XML配置文件。新建一个beans.xml，放到src目录下，确保在classpath中能找到此配置文件，输入以下内容：</p>
<pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;<a href="http://www.springframework.org/dtd/spring-beans.dtd"><u>http://www.springframework.org/dtd/spring-beans.dtd</u></a>&quot;&gt;&lt;beans&gt;&#160;&#160;&#160; &lt;bean id=&quot;service&quot; class=&quot;com.crackj2ee.example.spring.MyServiceBean&quot; /&gt;&lt;/beans&gt;</pre>
<p>以上XML声明了一个id为service的Bean，默认地，Spring为每个声明的Bean仅创建一个实例，并通过id来引用这个Bean。下面，我们修改main方法，让Spring来管理业务Bean：</p>
<pre>/** * Copyright_2006, Liao Xuefeng * Created on 2006-3-9 */package com.crackj2ee.example.spring;</pre>
<pre>import org.springframework.beans.factory.xml.XmlBeanFactory;import org.springframework.core.io.ClassPathResource;</pre>
<pre>public class Main {</pre>
<pre>&#160;&#160;&#160; public static void main(String[] args) throws Exception {&#160;&#160;&#160;&#160;&#160;&#160;&#160; // init factory:&#160;&#160;&#160;&#160;&#160;&#160;&#160; XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource(&quot;beans.xml&quot;));&#160;&#160;&#160;&#160;&#160;&#160;&#160; // use service bean:&#160;&#160;&#160;&#160;&#160;&#160;&#160; ServiceBean service = (ServiceBean)factory.getBean(&quot;service&quot;);&#160;&#160;&#160;&#160;&#160;&#160;&#160; service.addUser(&quot;bill&quot;, &quot;hello&quot;);&#160;&#160;&#160;&#160;&#160;&#160;&#160; service.addUser(&quot;tom&quot;, &quot;goodbye&quot;);&#160;&#160;&#160;&#160;&#160;&#160;&#160; service.addUser(&quot;tracy&quot;, &quot;morning&quot;);&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println(&quot;tom's password is \&quot;&quot; + service.getPassword(&quot;tom&quot;) + &quot;\&quot;&quot;);&#160;&#160;&#160;&#160;&#160;&#160;&#160; if(service.findUser(&quot;tom&quot;)) {&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; service.deleteUser(&quot;tom&quot;);&#160;&#160;&#160;&#160;&#160;&#160;&#160; }&#160;&#160;&#160;&#160;&#160;&#160;&#160; // close factory:&#160;&#160;&#160;&#160;&#160;&#160;&#160; factory.destroySingletons();&#160;&#160;&#160; }}</pre>
<p>执行结果：</p>
<p><img height="183" alt="" src="http://www.javaeedev.com/upload/14/8/ff80808112ccf1bc0112d1f256900043.jpg" width="566" /></p>
<p>由于我们要通过main方法启动Spring环境，因此，首先需要初始化一个BeanFactory。红色部分是初始化Spring的BeanFactory的典型代码，只需要保证beans.xml文件位于classpath中。</p>
<p>然后，在BeanFactory中通过id查找，即可获得相应的Bean的实例，并将其适当转型为合适的接口。</p>
<p>接着，实现一系列业务操作，在应用程序结束前，让Spring销毁所有的Bean实例。</p>
<p>对比上一个版本的Main，可以看出，最大的变化是不需要自己管理Bean的生命周期。另一个好处是在不更改实现类的前提下，动态地为应用程序增加功能。</p>
<h5>4．编写Advisor以增强ServiceBean</h5>
<p>所谓AOP即是将分散在各个方法处的公共代码提取到一处，并通过类似拦截器的机制实现代码的动态织入。可以简单地想象成，在某个方法的调用前、返回前、调用后和抛出异常时，动态插入自己的代码。在弄清楚Pointcut、Advice之类的术语前，不如编写一个最简单的AOP应用来体验一下。</p>
<p>考虑一下通常的Web应用程序都会有日志记录，我们来编写一个LogAdvisor，对每个业务方法调用前都作一个记录：</p>
<pre>/** * Copyright_2006, Liao Xuefeng * Created on 2006-3-9 */package com.crackj2ee.example.spring;</pre>
<pre>import java.lang.reflect.Method;import org.springframework.aop.MethodBeforeAdvice;</pre>
<pre>public class LogAdvisor implements MethodBeforeAdvice {&#160;&#160;&#160; public void before(Method m, Object[] args, Object target) throws Throwable {&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println(&quot;[Log] &quot; + target.getClass().getName() + &quot;.&quot; + m.getName() + &quot;()&quot;);&#160;&#160;&#160; }}</pre>
<p>然后，修改beans.xml：</p>
<pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;<a href="http://www.springframework.org/dtd/spring-beans.dtd"><u>http://www.springframework.org/dtd/spring-beans.dtd</u></a>&quot;&gt;</pre>
<pre>&lt;beans&gt;&#160;&#160;&#160; &lt;bean id=&quot;serviceTarget&quot; class=&quot;com.crackj2ee.example.spring.MyServiceBean&quot; /&gt;</pre>
<pre>&#160;&#160;&#160; &lt;bean id=&quot;logAdvisor&quot; class=&quot;com.crackj2ee.example.spring.LogAdvisor&quot; /&gt;</pre>
<pre>&#160;&#160;&#160; &lt;bean id=&quot;service&quot; class=&quot;org.springframework.aop.framework.ProxyFactoryBean&quot;&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;proxyInterfaces&quot;&gt;&lt;value&gt;com.crackj2ee.example.spring.ServiceBean&lt;/value&gt;&lt;/property&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;target&quot;&gt;&lt;ref local=&quot;serviceTarget&quot;/&gt;&lt;/property&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;interceptorNames&quot;&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;list&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;value&gt;logAdvisor&lt;/value&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/list&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;&#160;&#160;&#160; &lt;/bean&gt;&lt;/beans&gt;</pre>
<p>注意观察修改后的配置文件，我们使用了一个ProxyFactoryBean作为service来与客户端打交道，而真正的业务Bean即 MyServiceBean被声明为serviceTarget并作为参数对象传递给ProxyFactoryBean，proxyInterfaces 指定了返回的接口类型。对于客户端而言，将感觉不出任何变化，但却动态加入了LogAdvisor，关系如下：</p>
<p><img height="106" alt="" src="http://www.javaeedev.com/upload/14/8/ff80808112ccf1bc0112d1f308e30044.jpg" width="382" /></p>
<p>运行结果如下，可以很容易看到调用了哪些方法： </p>
<p><img alt="" src="http://www.javaeedev.com/upload/2/1/ff80808112ccf1bc0112d1f3f6970045.jpg" /></p>
<p>要截获指定的某些方法也是可以的。下面的例子将修改getPassword()方法的返回值：</p>
<pre>/** * Copyright_2006, Liao Xuefeng * Created on 2006-3-9 * For more information, please visit: <a href="http://www.crackj2ee.com/"><u>http://www.crackj2ee.com</u></a> */package com.crackj2ee.example.spring;</pre>
<pre>import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;</pre>
<pre>public class PasswordAdvisor implements MethodInterceptor {&#160;&#160;&#160; public Object invoke(MethodInvocation invocation) throws Throwable {&#160;&#160;&#160;&#160;&#160;&#160;&#160; Object ret = invocation.proceed();&#160;&#160;&#160;&#160;&#160;&#160;&#160; if(ret==null)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return null;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String password = (String)ret;&#160;&#160;&#160;&#160;&#160;&#160;&#160; StringBuffer encrypt = new StringBuffer(password.length());&#160;&#160;&#160;&#160;&#160;&#160;&#160; for(int i=0; i&lt;password.length(); i++)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; encrypt.append('*');&#160;&#160;&#160;&#160;&#160;&#160;&#160; return encrypt.toString();&#160;&#160;&#160; }}</pre>
<p>这个PasswordAdvisor将截获ServiceBean的getPassword()方法的返回值，并将其改为&quot;***&quot;。继续修改beans.xml：</p>
<pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;<a href="http://www.springframework.org/dtd/spring-beans.dtd"><u>http://www.springframework.org/dtd/spring-beans.dtd</u></a>&quot;&gt;&lt;beans&gt;&#160;&#160;&#160; &lt;bean id=&quot;serviceTarget&quot; class=&quot;com.crackj2ee.example.spring.MyServiceBean&quot; /&gt;</pre>
<pre>&#160;&#160;&#160; &lt;bean id=&quot;logAdvisor&quot; class=&quot;com.crackj2ee.example.spring.LogAdvisor&quot; /&gt;</pre>
<pre>&#160;&#160;&#160; &lt;bean id=&quot;passwordAdvisorTarget&quot; class=&quot;com.crackj2ee.example.spring.PasswordAdvisor&quot; /&gt;</pre>
<pre>&#160;&#160;&#160; &lt;bean id=&quot;passwordAdvisor&quot; class=&quot;org.springframework.aop.support.RegexpMethodPointcutAdvisor&quot;&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;advice&quot;&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;ref local=&quot;passwordAdvisorTarget&quot;/&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;patterns&quot;&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;list&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;value&gt;.*getPassword&lt;/value&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/list&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;&#160;&#160;&#160; &lt;/bean&gt;</pre>
<pre>&#160;&#160;&#160; &lt;bean id=&quot;service&quot; class=&quot;org.springframework.aop.framework.ProxyFactoryBean&quot;&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;proxyInterfaces&quot;&gt;&lt;value&gt;com.crackj2ee.example.spring.ServiceBean&lt;/value&gt;&lt;/property&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;target&quot;&gt;&lt;ref local=&quot;serviceTarget&quot;/&gt;&lt;/property&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;interceptorNames&quot;&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;list&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;value&gt;logAdvisor&lt;/value&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;value&gt;passwordAdvisor&lt;/value&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/list&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;&#160;&#160;&#160; &lt;/bean&gt;&lt;/beans&gt;</pre>
<p>利用Spring提供的一个RegexMethodPointcutAdvisor可以非常容易地指定要截获的方法。运行结果如下，可以看到返回结果变为&quot;******&quot;：</p>
<p><img alt="" src="http://www.javaeedev.com/upload/0/3/ff80808112ccf1bc0112d1f46e320046.jpg" /></p>
<p>还需要继续增强ServiceBean？我们编写一个ExceptionAdvisor，在业务方法抛出异常时能做一些处理：</p>
<pre>/** * Copyright_2006, Liao Xuefeng * Created on 2006-3-9 */package com.crackj2ee.example.spring;</pre>
<pre>import org.springframework.aop.ThrowsAdvice;</pre>
<pre>public class ExceptionAdvisor implements ThrowsAdvice {&#160;&#160;&#160; public void afterThrowing(RuntimeException re) throws Throwable {&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println(&quot;[Exception] &quot; + re.getMessage());&#160;&#160;&#160; }}</pre>
<p>将此Advice添加到beans.xml中，然后在业务Bean中删除一个不存在的用户，故意抛出异常：</p>
<pre>service.deleteUser(&quot;not-exist&quot;);</pre>
<p>再次运行，注意到ExceptionAdvisor记录下了异常：</p>
<p><img alt="" src="http://www.javaeedev.com/upload/15/3/ff80808112ccf1bc0112d1f4e37f0047.jpg" /></p>
<h5>5．总结</h5>
<p>利用Spring非常强大的IoC容器和AOP功能，我们能实现非常灵活的应用，让Spring容器管理业务对象的生命周期，利用AOP增强功能，却不影响业务接口，从而避免更改客户端代码。</p>
<p>为了实现这一目标，必须始终牢记：面向接口编程。而Spring默认的AOP代理也是通过Java的代理接口实现的。虽然Spring也可以用CGLIB实现对普通类的代理，但是，业务对象只要没有接口，就会变得难以扩展、维护和测试。</p>
<p>欢迎留言讨论</p>
<p>可以从此处<a href="http://javaeedev.googlecode.com/files/SpringBasic.zip"><u>下载完整的Eclipse工程</u></a></p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-eclipse-242/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MyEclipse生成的Spring+Hibernate无法保存数据问题2</title>
		<link>http://javadou.com/myeclipse-spring-hibernate-save-database-2-241/</link>
		<comments>http://javadou.com/myeclipse-spring-hibernate-save-database-2-241/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 02:41:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[MyEclipse]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[myeclipse]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/myeclipse-spring-hibernate-save-database-2-241/</guid>
		<description><![CDATA[MyEclipse生成的Spring+Hibernate无法保存数据问题的解决方法2 - 用 CGLIB 来实现事务管理

  上一小节讨论了用 JDK 的代理机制来实现事务管理的解决方案, 相比起来它有一个麻烦的地方就是必须需要生成一个 DAO 的接口才能... ]]></description>
			<content:encoded><![CDATA[<p>&#160; MyEclipse生成的Spring+Hibernate无法保存数据问题的解决方法2 &#8211; 用 CGLIB 来实现事务管理</p>
<p>&#160; 上一小节讨论了用 JDK 的代理机制来实现事务管理的解决方案, 相比起来它有一个麻烦的地方就是必须需要生成一个 DAO 的接口才能工作. 那么另一种比较简单的解决方案就是用 CGBLIB, 可以不用编写接口, 那么下面是 Spring 参考文档中的内容:   <br />7.5.3. 基于JDK和CGLIB的代理    <br />这个小节作为说明性文档，解释了对于一个目标对象（需要被代理的对象），ProxyFactryBean是如何决定究竟创建一个基于JDK还是CGLIB的代理的。 </p>
<p>注意   <br />ProxyFactoryBean需要创建基于JDK还是CGLIB代理的具体行为在版本1.2.x和2.0中有所不同。现在ProxyFactoryBean在关于自动检测接口方面使用了与TransactionProxyFactoryBean相似的语义。 </p>
<p>如果一个需要被代理的目标对象的类（后面将简单地称它为目标类）没有实现任何接口，那么一个基于CGLIB的代理将被创建。这是最简单的场景，因为 JDK代理是基于接口的，没有接口意味着没有使用JDK进行代理的可能。在目标bean里将被插入探测代码，通过interceptorNames属性给出了拦截器的列表。注意一个基于CGLIB的代理将被创建即使 ProxyFactoryBean的proxyTargetClass属性被设置为false。（很明显这种情况下对这个属性进行设置是没有意义的，最好把它从bean的定义中移除，因为虽然这只是个多余的属性，但在许多情况下会引起混淆。） </p>
<p>如果目标类实现了一个（或者更多）接口，那么创建代理的类型将根据ProxyFactoryBean的配置来决定。 </p>
<p>如果ProxyFactoryBean的proxyTargetClass属性被设为true，那么一个基于CGLIB的代理将创建。这样的规定是有意义的，遵循了最小惊讶法则（保证了设定的一致性）。甚至当ProxyFactoryBean的proxyInterfaces属性被设置为一个或者多个全限定接口名，而proxyTargetClass属性被设置为true仍然将实际使用基于CGLIB的代理。 </p>
<p>如果ProxyFactoryBean的proxyInterfaces属性被设置为一个或者多个全限定接口名，一个基于JDK的代理将被创建。被创建的代理将实现所有在proxyInterfaces属性里被说明的接口；如果目标类实现了全部在proxyInterfaces属性里说明的接口以及一些额外接口，返回的代理将只实现说明的接口而不会实现那些额外接口。 </p>
<p>如果ProxyFactoryBean的proxyInterfaces属性没有被设置，但是目标类实现了一个（或者更多）接口，那么 ProxyFactoryBean将自动检测到这个目标类已经实现了至少一个接口，一个基于JDK的代理将被创建。被实际代理的接口将是目标类所实现的全部接口；实际上，这和在proxyInterfaces属性中列出目标类实现的每个接口的情况是一样的。然而，这将显著地减少工作量以及输入错误的可能性。 </p>
<p>好了, 详细阐述这个解决方案.</p>
<p>用 MyEclipse 的自动生成功能产生的 Spring + Hibernate 的 DAO 有时候会出现不能保存数据但是可以查询数据的问题, 这是因为默认生成的 Spring 配置文件里面没有包含对事务的操作, 也就是没有 commit Hibernate transaction 的调用所以无法保存数据. 也就是正确的调用需要 beginTran, save, commit, 但是现在就少了 tran 的调用代码部分. 因为刚刚接触 Spring 这个 &quot;轻量级&quot; 非侵入框架不久, 所以好多问题不是太熟悉, 最近收集了一些资料看了看总算解决了问题. 有问题不要紧, 只要能通过学习来解决它就可以了, 我个人并不很喜欢没事去精通 XXX 框架, 而是喜欢做一些解决问题和查资料能力的锻炼, 有了后面所提的能力, 不管改天是不是出了个 Winter 框架, 也不会担心落伍, 当然前提是基础知识要牢固, 否则很容易看不懂. </p>
<p>解决方法是在配置文件里&quot;侵入性&quot;(必须这样做, 做额外的配置, 否则就无法正常工作, 所以是侵入性的)的加入事务配置后就可以正常的保存数据到 Derby, Oracle 等数据了:</p>
<p>1. 修改配置文件给原来的 UsersDAO 加入代理类来进行事务管理:   <br />&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;    <br />&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;    <br /> xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;    <br /> xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;</p>
<p> &lt;bean id=&quot;sessionFactory&quot;   <br />&#160; class=&quot;org.springframework.orm.hibernate3.LocalSessionFactoryBean&quot;&gt;    <br />&#160; &lt;property name=&quot;configLocation&quot;    <br />&#160;&#160; value=&quot;file:src/hibernate.cfg.xml&quot;&gt;    <br />&#160; &lt;/property&gt;    <br /> &lt;/bean&gt;</p>
<p> &lt;!&#8211; UsersDAO &#8211;&gt;   <br /> &lt;bean id=&quot;UsersDAO&quot; class=&quot;dao.UsersDAO&quot;&gt;    <br />&#160; &lt;property name=&quot;sessionFactory&quot;&gt;    <br />&#160;&#160; &lt;ref bean=&quot;sessionFactory&quot; /&gt;    <br />&#160; &lt;/property&gt;    <br /> &lt;/bean&gt;</p>
<p> &lt;!&#8211; 以下两个 Bean transactionManager 和 userDAOProxy 是新加入的内容, 用来配置事务 &#8211;&gt;</p>
<p> &lt;!&#8211; 声明一个 Hibernate 3 的 事务管理器供代理类自动管理事务用 &#8211;&gt;   <br /> &lt;bean id=&quot;transactionManager&quot;    <br />&#160; class=&quot;org.springframework.orm.hibernate3.HibernateTransactionManager&quot;&gt;    <br />&#160; &lt;property name=&quot;sessionFactory&quot;&gt;    <br />&#160;&#160; &lt;ref local=&quot;sessionFactory&quot; /&gt;    <br />&#160; &lt;/property&gt;    <br /> &lt;/bean&gt;</p>
<p> &lt;!&#8211; 这个代理类是最后对外公开的类, 否则因为没有进行事务操作,    <br /> 保存时没有提交 hibernate 的事务, 这将无法对数据库进行改动, 也就是原来要调用 UsersDAO 的地方都要转而调用这个代理对象 userDAOProxy; 具体的属性配置在 target 参数那里指定了这个对象对原来的 UsersDAO 对象进行代理;    <br /> 也因为要使用代理, 只有通过它来作为原来配置的 UsersDAO 的代理工作, 才能让 Spring 在保存数据的时候自动打开 Hibernate 的 Transaction 并提交, 即属性 transactionManager 配置的 HibernateTransactionManager &#8211;&gt;    <br /> &lt;bean id=&quot;userDAOProxy&quot;    <br />&#160; class=&quot;org.springframework.transaction.interceptor.TransactionProxyFactoryBean&quot;&gt;</p>
<p>&#160; &lt;!&#8211; 注意这个属性, 详细意义请参考文章开头的参考资料, 必须为 true 使用CGLIB才不用强制编写DAO接口 &#8211;&gt;   <br />&#160; &lt;property name=&quot;proxyTargetClass&quot;&gt;    <br />&#160;&#160; &lt;value&gt;true&lt;/value&gt;    <br />&#160; &lt;/property&gt;</p>
<p>&#160; &lt;property name=&quot;transactionManager&quot;&gt;   <br />&#160;&#160; &lt;ref bean=&quot;transactionManager&quot; /&gt;    <br />&#160; &lt;/property&gt;    <br />&#160; &lt;property name=&quot;target&quot;&gt;    <br />&#160;&#160; &lt;ref local=&quot;UsersDAO&quot; /&gt;    <br />&#160; &lt;/property&gt;    <br />&#160; &lt;property name=&quot;transactionAttributes&quot;&gt;    <br />&#160;&#160; &lt;props&gt;    <br />&#160;&#160;&#160; &lt;!&#8211; 这里的方法签名可以精确到方法, 先懒惰一下全配置上 &#8211;&gt;    <br />&#160;&#160;&#160; &lt;prop key=&quot;*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160; &lt;/props&gt;    <br />&#160; &lt;/property&gt;    <br /> &lt;/bean&gt;</p>
<p>&lt;/beans&gt;</p>
<p>2. 修改调用代码, 原来调用 UsersDAO 的地方都要转而调用 userDAOProxy, 因为用了 CGLIB, 所以类型转换不会发生异常.   <br />&#160; 原始代码:    <br />&#160; UsersDAO dao = applicationContext.getBean(&quot;UsersDAO&quot;);    <br />&#160; dao.save(users);// 可能无法保存数据, 因为没有事务管理    <br />&#160; 修改为:    <br />&#160; UsersDAO dao = applicationContext.getBean(&quot;userDAOProxy&quot;);    <br />&#160; dao.save(users);// 现在应该 OK 了, 因为事务提交了</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/myeclipse-spring-hibernate-save-database-2-241/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MyEclipse生成Spring+Hibernate无法保存数据问题解决方法</title>
		<link>http://javadou.com/myeclipse-spring-hibernate-save-database-240/</link>
		<comments>http://javadou.com/myeclipse-spring-hibernate-save-database-240/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 01:40:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[MyEclipse]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[myeclipse]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/myeclipse-spring-hibernate-save-database-240/</guid>
		<description><![CDATA[用 MyEclipse 的自动生成功能产生的 Spring + Hibernate 的 DAO 有时候会出现不能保存数据但是可以查询数据的问题, 这是因为默认生成的 Spring 配置文件里面没有包含对事务的操作, 也就是没有 commit Hibernate transaction 的调用... ]]></description>
			<content:encoded><![CDATA[<p>MyEclipse生成的Spring+Hibernate无法保存数据问题的解决方法</p>
<p>用 MyEclipse 的自动生成功能产生的 Spring + Hibernate 的 DAO 有时候会出现不能保存数据但是可以查询数据的问题, 这是因为默认生成的 Spring 配置文件里面没有包含对事务的操作, 也就是没有 commit Hibernate transaction 的调用所以无法保存数据. 也就是正确的调用需要 beginTran, save, commit, 但是现在就少了 tran 的调用代码部分. 因为刚刚接触 Spring 这个 &#8220;轻量级&#8221; 非侵入框架不久, 所以好多问题不是太熟悉, 最近收集了一些资料看了看总算解决了问题. 有问题不要紧, 只要能通过学习来解决它就可以了, 我个人并不很喜欢没事去精通 XXX 框架, 而是喜欢做一些解决问题和查资料能力的锻炼, 有了后面所提的能力, 不管改天是不是出了个 Winter 框架, 也不会担心落伍, 当然前提是基础知识要牢固, 否则很容易看不懂.</p>
<p>解决方法是在配置文件里&#8221;侵入性&#8221;(必须这样做, 做额外的配置和修改, 否则就无法正常工作, 所以是侵入性的)的加入事务配置后就可以正常的保存数据到 Derby, Oracle 等数据了, 也有其它的解决办法, 希望用 Spring 比较早的经验多的人提出建议:</p>
<p>1. 用 Ecipse 的重构给自动生成的 UsersDAO 类添加一个接口, 里面包含所有的方法声明, 例如 IUsersDAO, 加入接口的目的是为了使用 JDK 的动态代理方式实现的 Spring AOP 来工作, 也有另一种解决方案使用 CGLIB 的话就不需要这一步了, 这种方式下一次讨论.</p>
<p>public interface IUsersDAO {</p>
<p>public abstract void save(Users transientInstance);<br />
}</p>
<p>public class UsersDAO extends HibernateDaoSupport implements IUsersDAO {<br />
&#8230;<br />
public void save(Users transientInstance) {<br />
log.debug(&#8220;saving Users instance&#8221;);<br />
try {<br />
getHibernateTemplate().save(transientInstance);<br />
log.debug(&#8220;save successful&#8221;);<br />
} catch (RuntimeException re) {<br />
log.error(&#8220;save failed&#8221;, re);<br />
throw re;<br />
}<br />
&#8230;<br />
}</p>
<p>2. 修改配置文件给原来的 UsersDAO 加入代理类来进行事务管理:<br />
&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;UTF-8&#8243;?&gt;<br />
&lt;beans xmlns=&#8221;http://www.springframework.org/schema/beans&#8221;<br />
xmlns:xsi=&#8221;http://www.w3.org/2001/XMLSchema-instance&#8221;<br />
xsi:schemaLocation=&#8221;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&#8221;&gt;</p>
<p>&lt;bean id=&#8221;sessionFactory&#8221;<br />
class=&#8221;org.springframework.orm.hibernate3.LocalSessionFactoryBean&#8221;&gt;<br />
&lt;property name=&#8221;configLocation&#8221;<br />
value=&#8221;file:src/hibernate.cfg.xml&#8221;&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;</p>
<p>&lt;!&#8211; UsersDAO implements IUsersDAO 接口 &#8211;&gt;<br />
&lt;bean id=&#8221;UsersDAO&#8221; class=&#8221;dao.UsersDAO&#8221;&gt;<br />
&lt;property name=&#8221;sessionFactory&#8221;&gt;<br />
&lt;ref bean=&#8221;sessionFactory&#8221; /&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;</p>
<p>&lt;!&#8211; 以下两个 Bean transactionManager 和 userDAOProxy 是新加入的内容, 用来配置事务 &#8211;&gt;</p>
<p>&lt;!&#8211; 声明一个 Hibernate 3 的 事务管理器供代理类自动管理事务用 &#8211;&gt;<br />
&lt;bean id=&#8221;transactionManager&#8221;<br />
class=&#8221;org.springframework.orm.hibernate3.HibernateTransactionManager&#8221;&gt;<br />
&lt;property name=&#8221;sessionFactory&#8221;&gt;<br />
&lt;ref local=&#8221;sessionFactory&#8221; /&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;</p>
<p>&lt;!&#8211; 这个代理类是最后对外公开的类, 否则因为没有进行事务操作,<br />
保存时没有提交 hibernate 的事务, 这将无法对数据库进行改动, 也就是原来要调用 UsersDAO 的地方都要转而调用这个代理对象 userDAOProxy; 具体的属性配置在 target 参数那里指定了这个对象对原来的 UsersDAO 对象进行代理;<br />
也因为要使用动态代理, 所以这里必须给 UsersDAO 抽象一个接口 IUsersDAO, 只有通过它来作为原来配置的 UsersDAO 的代理工作, 才能让 Spring 在保存数据的时候自动打开 Hibernate 的 Transaction 并提交, 即属性 transactionManager 配置的 HibernateTransactionManager &#8211;&gt;<br />
&lt;bean id=&#8221;userDAOProxy&#8221;<br />
class=&#8221;org.springframework.transaction.interceptor.TransactionProxyFactoryBean&#8221;&gt;<br />
&lt;property name=&#8221;transactionManager&#8221;&gt;<br />
&lt;ref bean=&#8221;transactionManager&#8221; /&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;target&#8221;&gt;<br />
&lt;ref local=&#8221;UsersDAO&#8221; /&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;transactionAttributes&#8221;&gt;<br />
&lt;props&gt;<br />
&lt;!&#8211; 这里的方法签名可以精确到方法, 先懒惰一下全配置上 &#8211;&gt;<br />
&lt;prop key=&#8221;*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;/props&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;</p>
<p>&lt;/beans&gt;</p>
<p>3. 修改调用代码, 原来调用 UsersDAO 的地方都要转而调用 userDAOProxy, 而且转换后的目标要修改为 IUsersDAO, 否则就会报 ClassCastException, 具体原因参考 Spring 的 AOP 实现部分的内容, 也可以用 cglib 来解决.<br />
原始代码:<br />
UsersDAO dao = applicationContext.getBean(&#8220;UsersDAO&#8221;);<br />
dao.save(users);// 可能无法保存数据, 因为没有事务管理<br />
修改为:<br />
IUsersDAO dao = applicationContext.getBean(&#8220;userDAOProxy&#8221;);<br />
dao.save(users);// 现在应该 OK 了, 因为事务提交了</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/myeclipse-spring-hibernate-save-database-240/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Spring 整合 Hibernate + Mysql 的代码</title>
		<link>http://javadou.com/spring-hibernate-mysql-code-239/</link>
		<comments>http://javadou.com/spring-hibernate-mysql-code-239/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 22:38:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-hibernate-mysql-code-239/</guid>
		<description><![CDATA[开始用的是 MyEclipse 自带的 Derby 数据库,  发现单独的 Hibernate DAO 没有问题, 一整合 Spring 就插入不了数据, 甚至按照参考资料上的将 HibernateTransactionManager 的加进去也无济于事. 今天换成了 Mysql 就好了, 调试信息全打开... ]]></description>
			<content:encoded><![CDATA[<p>开始用的是 MyEclipse 自带的 Derby 数据库,  发现单独的 Hibernate DAO 没有问题, 一整合 Spring 就插入不了数据, 甚至按照参考资料上的将 HibernateTransactionManager 的加进去也无济于事. 今天换成了 Mysql 就好了, 调试信息全打开也没看到什么出错, 不知原因, 甚是郁闷.</p>
<p><strong>原因已经找到, 事务管理器没加对.具体解决方案请参考:</strong></p>
<p><strong><a href="http://javadou.com/myeclipse-spring-hibernate-save-database-240/" target="_blank">MyEclipse生成的Spring+Hibernate无法保存数据问题的解决方法</a></strong></p>
<p><strong><a href="http://myeclipse-spring-hibernate-save-database-2-241/" target="_blank">MyEclipse生成的Spring+Hibernate无法保存数据问题的解决方法2 &#8211; 用 CGLIB 来实现事务管理</a></strong></p>
<p>可以新建一个 Java Project 然后添加 Hibernate 和 Spring 开发功能就能测试本文提到的代码了.</p>
<p>建表的 SQL:</p>
<pre class="sql">CREATE TABLE `usertable` (
  `id` int(11) NOT NULL,
  `username` varchar(200) NOT NULL,
  `password` varchar(20) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=GBK;</pre>
<p>src/TestSpringHibernateDAO.java</p>
<pre class="java">import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import entity.Usertable;

import spring_hibernate_dao.UsertableDAO;

public class TestSpringHibernateDAO {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
        "applicationContext.xml");

        UsertableDAO dao = UsertableDAO.getFromApplicationContext(ctx);

        Usertable user = new Usertable();
        user.setId(5);
        user.setUsername("5");
        user.setPassword("5");

        dao.save(user);
    }

}</pre>
<p>src/entity/Usertable.java</p>
<pre class="java">package entity;

public class Usertable implements java.io.Serializable {

    // Fields

    private Integer id;

    private String username;

    private String password;

    // Constructors

    /** default constructor */
    public Usertable() {
    }

    /** full constructor */
    public Usertable(Integer id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    // Property accessors

    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return this.username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return this.password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}</pre>
<p>src/entity/Usertable.hbm.xml</p>
<pre class="xml">
&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&gt;&lt;hibernate-mapping&gt;&lt;class name="entity.Usertable" table="usertable" catalog="test"&gt;&lt;id name="id" type="java.lang.Integer"&gt;&lt;column name="id" /&gt;&lt;generator class="assigned" /&gt;&lt;/id&gt;&lt;property name="username" type="java.lang.String"&gt;&lt;column name="username" length="200" not-null="true" /&gt;&lt;/property&gt;&lt;property name="password" type="java.lang.String"&gt;&lt;column name="password" length="20" not-null="true" /&gt;&lt;/property&gt;&lt;/class&gt;&lt;/hibernate-mapping&gt;</pre>
<p>src/spring_hibernate_dao/UsertableDAO.java</p>
<pre class="java">package spring_hibernate_dao;

import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.LockMode;
import org.springframework.context.ApplicationContext;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import entity.Usertable;

/**
 * Data access object (DAO) for domain model class Usertable.
 *
 * @see spring_hibernate_dao.Usertable
 * @author MyEclipse Persistence Tools
 */

public class UsertableDAO extends HibernateDaoSupport {
    private static final Log log = LogFactory.getLog(UsertableDAO.class);

    // property constants
    public static final String USERNAME = "username";

    public static final String PASSWORD = "password";

    protected void initDao() {
        // do nothing
    }

    public void save(Usertable transientInstance) {
        log.debug("saving Usertable instance");
        try {
            getHibernateTemplate().save(transientInstance);
            log.debug("save successful");
        } catch (RuntimeException re) {
            log.error("save failed", re);
            throw re;
        }
    }

    public void delete(Usertable persistentInstance) {
        log.debug("deleting Usertable instance");
        try {
            getHibernateTemplate().delete(persistentInstance);
            log.debug("delete successful");
        } catch (RuntimeException re) {
            log.error("delete failed", re);
            throw re;
        }
    }

    public Usertable findById(java.lang.Integer id) {
        log.debug("getting Usertable instance with id: " + id);
        try {
            Usertable instance = (Usertable) getHibernateTemplate().get(
                    "spring_hibernate.Usertable", id);
            return instance;
        } catch (RuntimeException re) {
            log.error("get failed", re);
            throw re;
        }
    }

    public List findByExample(Usertable instance) {
        log.debug("finding Usertable instance by example");
        try {
            List results = getHibernateTemplate().findByExample(instance);
            log.debug("find by example successful, result size: "
                    + results.size());
            return results;
        } catch (RuntimeException re) {
            log.error("find by example failed", re);
            throw re;
        }
    }

    public List findByProperty(String propertyName, Object value) {
        log.debug("finding Usertable instance with property: " + propertyName
                + ", value: " + value);
        try {
            String queryString = "from Usertable as model where model."
                    + propertyName + "= ?";
            return getHibernateTemplate().find(queryString, value);
        } catch (RuntimeException re) {
            log.error("find by property name failed", re);
            throw re;
        }
    }

    public List findByUsername(Object username) {
        return findByProperty(USERNAME, username);
    }

    public List findByPassword(Object password) {
        return findByProperty(PASSWORD, password);
    }

    public List findAll() {
        log.debug("finding all Usertable instances");
        try {
            String queryString = "from Usertable";
            return getHibernateTemplate().find(queryString);
        } catch (RuntimeException re) {
            log.error("find all failed", re);
            throw re;
        }
    }

    public Usertable merge(Usertable detachedInstance) {
        log.debug("merging Usertable instance");
        try {
            Usertable result = (Usertable) getHibernateTemplate().merge(
                    detachedInstance);
            log.debug("merge successful");
            return result;
        } catch (RuntimeException re) {
            log.error("merge failed", re);
            throw re;
        }
    }

    public void attachDirty(Usertable instance) {
        log.debug("attaching dirty Usertable instance");
        try {
            getHibernateTemplate().saveOrUpdate(instance);
            log.debug("attach successful");
        } catch (RuntimeException re) {
            log.error("attach failed", re);
            throw re;
        }
    }

    public void attachClean(Usertable instance) {
        log.debug("attaching clean Usertable instance");
        try {
            getHibernateTemplate().lock(instance, LockMode.NONE);
            log.debug("attach successful");
        } catch (RuntimeException re) {
            log.error("attach failed", re);
            throw re;
        }
    }

    public static UsertableDAO getFromApplicationContext(ApplicationContext ctx) {
        return (UsertableDAO) ctx.getBean("UsertableDAO");
    }
}</pre>
<p>src/applicationContext.xml</p>
<pre class="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;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.0.xsd"&gt;

&lt;bean id="sessionFactory"

        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt;

&lt;property name="configLocation"

            value="file:src/hibernate.cfg.xml"&gt;

&lt;/property&gt;

&lt;/bean&gt;

&lt;bean id="UsertableDAO" class="spring_hibernate_dao.UsertableDAO"&gt;

&lt;property name="sessionFactory"&gt;

&lt;ref bean="sessionFactory" /&gt;

&lt;/property&gt;

&lt;/bean&gt;

&lt;/beans&gt;</pre>
<pre class="xml">src/hibernate.cfg.xml

&lt;?xml version='1.0' encoding='UTF-8'?&gt;
  &lt;!DOCTYPE hibernate-configuration PUBLIC

          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"&gt;

&lt;hibernate-configuration&gt;

&lt;session-factory&gt;

&lt;property name="connection.username"&gt;root&lt;/property&gt;

&lt;property name="connection.url"&gt;

            jdbc:mysql://localhost/test

&lt;/property&gt;

&lt;property name="dialect"&gt;

            org.hibernate.dialect.MySQLDialect

&lt;/property&gt;

&lt;property name="myeclipse.connection.profile"&gt;

            mysql localhost

&lt;/property&gt;

&lt;property name="connection.driver_class"&gt;

            com.mysql.jdbc.Driver

&lt;/property&gt;

&lt;mapping resource="entity/Usertable.hbm.xml" /&gt;

&lt;/session-factory&gt;

&lt;/hibernate-configuration&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-hibernate-mysql-code-239/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MyEclipse 开发 Spring入门教程</title>
		<link>http://javadou.com/myeclipse-dev-spring-236/</link>
		<comments>http://javadou.com/myeclipse-dev-spring-236/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 21:31:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[MyEclipse]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[myeclipse]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/myeclipse-dev-spring-236/</guid>
		<description><![CDATA[1. 新建普通 Java 项目 MySpringTest. 这个过程无需赘述了, 建议建项目的时候将 src 目录和 bin(或者classes)目录分开, 另外提示你切换透视图的时候一定要切换过去到 Java 透视图, 此时默认会在 Package Explorer 中选中刚才已经... ]]></description>
			<content:encoded><![CDATA[<p>今天介绍的第二个课题就是介绍 Spring 的快速开发, 说是快速开发, 其实能帮助的地方除了语法高亮和自动添加类库外也没多少东西了.</p>
<p>1. 新建普通 Java 项目 MySpringTest. 这个过程无需赘述了, 建议建项目的时候将 src 目录和 bin(或者classes)目录分开, 另外提示你切换透视图的时候一定要切换过去到 Java 透视图, 此时默认会在 Package Explorer 中选中刚才已经建好的 Java Project, 但是背景为灰色.<br />
2. 首先单击一下左边的 Package Explorer 中新建的 MySpringTest 项目来使其高亮选中, 接着点击菜单项 MyEclipse -&gt; Add Spring Capabilities&#8230;, 接着会弹出对话框 Add Spring Capabilities 提示你设置当前项目的 Spring 属性.<br />
对话框的第一页可以选择全部的 Spring 框架, 这是最保险的做法, 不过我们的例子只需要选中Spring 2.0 Core Libraries 就可以了. 点击 &#8220;Next&#8221; 继续.<br />
第二页是 Add Spring bean configuration file. 保持默认值不变就可以了. 最后点击 Finish.<br />
3. Spring 的开发没法自动生成 Bean, 这里大家只好手工来写了, 也很简单. 分别复制下面的三个代码, 然后在 MyEclipse src 目录上点击右键后选择菜单项 Paste 就可以生成 Java 类文件了.</p>
<p>public interface Action {<br />
public String execute(String str);<br />
}</p>
<p>public class UpperAction implements Action {<br />
private String message;<br />
public String getMessage() {<br />
return message;<br />
}<br />
public void setMessage(String string) {<br />
message = string;<br />
}<br />
public String execute(String str) {<br />
return (getMessage() + str).toUpperCase();<br />
}<br />
}</p>
<p>import org.springframework.context.ApplicationContext;<br />
import org.springframework.context.support.ClassPathXmlApplicationContext;</p>
<p>public class TestAction {</p>
<p>public static void main(String[] args) {<br />
ApplicationContext ctx = new ClassPathXmlApplicationContext(<br />
&#8220;applicationContext.xml&#8221;);<br />
Action bean = (Action) ctx.getBean(&#8220;theAction&#8221;);<br />
System.out.println(bean.execute(&#8220;Rod&#8221;));<br />
}<br />
}</p>
<p>4. 双击左侧在第2步生成的 applicationContext.xml, 然后选择菜单项 Window -&gt; Show View -&gt; Other&#8230;, 在弹出的对话框中选择 MyEclipse Enterprise Workbench 节点下的 Spring Beans 子节点打开视图 Spring Beans. 此视图讲出现在主界面的右下侧.</p>
<p>5. 展开此视图中的 MySpringTest 父节点, 并选中 src/applicationContext.xml 子节点, 在此节点上点击右键并选择弹出菜单项中的 New Bean 来打开 Create a new Spring bean 对话框, 并按照下图输入对应的内容.<br />
Bean Id: [theAction]<br />
Bean class: [UpperAction]<br />
接下来请单击一下 Tab 面板 Properties 并点击其中的 Add&#8230; 按钮, 在接下来弹出的 Property Wizard 对话框中按照下图输入/选择内容:<br />
Name: [message]<br />
Spring type: [value]<br />
Type: [java.lang.String]<br />
Value:[Hello_]<br />
最后点击两次 Finish 按钮关闭所有向导对话框. 然后点击菜单 File -&gt; Save. 此时可以看到 applicationContext.xml 的内容如下所示:</p>
<p>xmlns=&#8221;http://www.springframework.org/schema/beans&#8221;<br />
xmlns:xsi=&#8221;http://www.w3.org/2001/XMLSchema-instance&#8221;<br />
xsi:schemaLocation=&#8221;http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd&#8221;&gt;</p>
<p>lazy-init=&#8221;default&#8221; autowire=&#8221;default&#8221; dependency-check=&#8221;default&#8221;&gt;<br />
Hello_<br />
然后双击 Package Explorer 下 MySpringTest/src/TestAction.java 打开源代码, 然后点击菜单 Run -&gt; Run As -&gt; 1. Java Application, 如果没有错误的话将会出现如下的输入, 您的第一个 Hello Spring 运行成功了:<br />
log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).<br />
log4j:WARN Please initialize the log4j system properly.<br />
HELLO_ROD</p>
<p>接着您就可以对着参考书继续创建类, 修改 applicationContext.xml 做更多的练习了.</p>
<p>开发整合 Hibernate 的关键操作点截图:<br />
1. 在数据库浏览器中选择反向工程菜单;</p>
<p><img class="alignnone size-full wp-image-238" title="o_dbExplorer" src="http://javadou.com/wordpress/wp-content/uploads/2009/09/o_dbExplorer.jpg" alt="o_dbExplorer" width="618" height="663" /></p>
<p>2. 对话框的选项说明</p>
<p><img class="alignnone size-full wp-image-237" title="o_hiber_spring_reverse" src="http://javadou.com/wordpress/wp-content/uploads/2009/09/o_hiber_spring_reverse.jpg" alt="o_hiber_spring_reverse" width="615" height="596" /></p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/myeclipse-dev-spring-236/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring 学习重点个人小结</title>
		<link>http://javadou.com/spring-zongjie-235/</link>
		<comments>http://javadou.com/spring-zongjie-235/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 20:30:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-zongjie-235/</guid>
		<description><![CDATA[大家可以看到 DAO 的  HibernateSessionFactory 完全是配置出来的, 不用我们写一行 Hibernate 初始化的代码, Spring 已经帮我们做好了一切. 完整的代码大家可以下载附件. 但是大家也请注意, 我们的代码这样做也是依赖了 Spring ... ]]></description>
			<content:encoded><![CDATA[<p>Spring 这么多内容该看哪些? 我就根据我的理解谈一些个人的观点, 仅供参考. 欢迎讨论.</p>
<p>首先学习 Spring 等框架应该本着简化程序员负担, 加快开发速度的原则来进行, 而不是把框架的知识点都给学习, 练习一遍. 另外用 Spring 的时候也要注意不要过渡依赖 Spring 框架, 注意它们的宣传语是: 无侵入, 轻量级. 所以, 除非必要, 千万不要让 Spring 侵入你的代码啊, 例如哪些 Aware 接口, 不也是变相的侵入了你的代码嘛. 还有不要为了 Spring 而 Spring, 明明一段代码用 new JavaBean().setUsername(&quot;xxx&quot;) 这样的方式非常简练, 你非要整出个 bean 的配置文件来, 纯属多此一举. 所以无侵入只是个相对概念, 代码写少了, 但是 bean.xml 配置文件和 Spring.jar 你不能丢吧, 所以你已经被 Spring 侵入了, 而且以后想换第二家公司来做个框架解析你这些 XML 文件都困难呢, 因为 Spring 本身并不是可替换或者热插拔的, 换句话说所有用 Spring 的代码都已经被绑定到了 Spring 框架上.&#160; 好了, 先说一下目前了解的 Spring 的主要应用场合.</p>
<p>1. 依赖注入, 主要是把一些需要经常修改的内容提取为 Bean, 也是尽量能不提取就不提取, 要不然到最后那个 bean.xml 增加到了几千行你也就不会觉得这时候有什么方便的地方了;</p>
<p>2. 整合 Hibernate, 这个可以说是最强大最实用的功能了, 也是为什么一提到 Spring 后面总是跟着 Hibernate 的原因. 在文档的 12.2. Hibernate 有相关的介绍. 例如看看下面的调用代码:</p>
<p>import java.io.IOException;</p>
<p>import org.springframework.context.ApplicationContext;   <br />import org.springframework.context.support.ClassPathXmlApplicationContext;</p>
<p>import dao.Testuser;   <br />import dao.TestuserDAO;</p>
<p>// 调用 Hibernate DAO   <br />public class Test {</p>
<p> public static void main(String[] args) throws IOException {   <br />&#160; ApplicationContext context = new ClassPathXmlApplicationContext(&quot;applicationContext.xml&quot;);    <br />&#160; TestuserDAO dao =(TestuserDAO)context.getBean(&quot;userDAO&quot;);    <br />&#160; Testuser user = new Testuser();    <br />//&#160; user.setxxx&#8230;, 设置值.    <br />&#160; dao.save(user);    <br /> }</p>
<p>}</p>
<p>再看 DAO 的代码:</p>
<p>package dao;</p>
<p>import org.springframework.orm.hibernate3.support.HibernateDaoSupport;</p>
<p>/**   <br /> * Data access object (DAO) for domain model class Testuser.    <br /> */</p>
<p>public class TestuserDAO extends HibernateDaoSupport {</p>
<p> public void save(Testuser transientInstance) {   <br />&#160; getHibernateTemplate().save(transientInstance);    <br /> }</p>
<p> public void delete(Testuser persistentInstance) {   <br />&#160; getHibernateTemplate().delete(persistentInstance);</p>
<p> }</p>
<p>}</p>
<p>是不是感觉简单到令人难以置信?&#160; 要保存的实体 POJO 也很简单:   <br />package dao;</p>
<p>/**   <br /> * Testuser generated by MyEclipse Persistence Tools    <br /> */</p>
<p>public class Testuser implements java.io.Serializable {</p>
<p> // Fields</p>
<p> private Integer id;</p>
<p> private String username;</p>
<p> private Integer age;   <br /> getXXX();    <br /> setXXX();    <br />}</p>
<p>然后我们看主要的配置文件 applicationContext.xml 的内容:   <br />&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;    <br />&lt;beans    <br /> xmlns=&quot;http://www.springframework.org/schema/beans&quot;    <br /> xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;    <br /> xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;</p>
<p> &lt;bean id=&quot;userDAO&quot; class=&quot;dao.TestuserDAO&quot;&gt;   <br />&#160; &lt;property name=&quot;sessionFactory&quot;&gt;    <br />&#160;&#160; &lt;ref bean=&quot;hibernateSessionFactory&quot; /&gt;    <br />&#160; &lt;/property&gt;    <br /> &lt;/bean&gt;</p>
<p> &lt;bean id=&quot;hibernateSessionFactory&quot;   <br />&#160; class=&quot;org.springframework.orm.hibernate3.LocalSessionFactoryBean&quot;&gt;    <br />&#160; &lt;property name=&quot;configLocation&quot;    <br />&#160;&#160; value=&quot;file:src/hibernate.cfg.xml&quot;&gt;    <br />&#160; &lt;/property&gt;    <br /> &lt;/bean&gt;</p>
<p>&lt;/beans&gt;</p>
<p>大家可以看到 DAO 的&#160; HibernateSessionFactory 完全是配置出来的, 不用我们写一行 Hibernate 初始化的代码, Spring 已经帮我们做好了一切. 完整的代码大家可以下载附件. 但是大家也请注意, 我们的代码这样做也是依赖了 Spring 的框架, 其实功能强大和不依赖具体的框架本身就是个谬论, 你不用(依赖)它的框架又怎么能用到它的强大的功能呢?</p>
<p>3. 使用 JDBCTemplate 简化普通的 JDBC 代码编写, 这个大家可以去看参考文档(官方的 Spring Framework 开发参考手册, 中英文均可) &quot; 第 11 章 使用JDBC进行数据访问&quot;, 老师也介绍过了.</p>
<p>4. 整合 Struts, 也参考文档里的内容, 具体是 15.4. Struts., 让 Struts 的 Action 可以被注入内容.</p>
<p>5. AOP 功能, 我没用过, 只是听一些朋友介绍说他们用的有, 所以建议大家了解一下, 个人觉得挺难理解, 开发的时候也是完全依赖 Spring 的 API, 比较难做. AOP 是 Spring 后来加入的内容, 按照官方文档是&quot;锦上添花的内容&quot;, 其实就是捆绑了自己的 AOP, 而 Spring 最核心的内容当属依赖注入功能.</p>
<p>6.&#160; 事务管理, 据说有一些人在用. 但是感觉开发起来挺费劲的, 不如 EJB 3 的标注来的简便. 不过你被绑在了 Spring 框架上, 一般就只好用它自己做的这些个功能了.</p>
<p>7. 其它的 Spring MVC 等内容, 都是可选项, 具体来说开发工具支持上并不如 Struts 来的那么直接好用.</p>
<p>至于 Spring 的缺点:   <br />1. 不支持分布式访问,分布式事务和集群, 这些是 EJB 3 的优点, 但是 Spring 目前还不支持;    <br />2. 配置使用 XML 文件, 如果文件内容很多的话对维护的人来说是个负担;    <br />3. 提供 Spring 容器的只有一家公司(Interface21), 换句话说它是非标准的, 被个别公司垄断的技术, 不能像 EJB 那样可以换一家厂商的服务器, Spring 不存在第二家公司来做.</p>
<p>另外开发工具的支持上, MyEclipse 5 可以快速的 5 分钟就做好 Spring 整合 Hibernate 的框架代码. 如果大家有兴趣可以自己找点资料来看或者直接咨询我.</p>
<p>那么大家看了这篇文档希望能有一些自己的想法, 把内容 100% 掌握是不现实的, 而且过了一阵子不用就肯定会忘, 所以现在需要的是了解概念, 能跑一些基础的代码以后用到的话再深入研究.</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-zongjie-235/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring教程ioc 依赖注入原理学习</title>
		<link>http://javadou.com/spring-ioc-yuanli-234/</link>
		<comments>http://javadou.com/spring-ioc-yuanli-234/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 19:29:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[recommend]]></category>
		<category><![CDATA[ioc]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-ioc-yuanli-234/</guid>
		<description><![CDATA[和上面的 TestTemplate 类相比, 就会发现 new DriverManagerDataSource() 这个过程不用我们写了, 运行的时候会发现一切都执行的好好的, 也就是常说的 ExecuteAStatement 的 dataSource 这个属性被注入了. 

那么这个过程到底该如何理解... ]]></description>
			<content:encoded><![CDATA[<p>首先我们来看看 Spring 参考文档的 11.2.6. 执行SQL语句 这里有个代码片断:</p>
<p>import javax.sql.DataSource;   <br />import org.springframework.jdbc.core.JdbcTemplate;</p>
<p>public class ExecuteAStatement {</p>
<p>&#160;&#160;&#160; private JdbcTemplate jt;   <br />&#160;&#160;&#160; private DataSource dataSource;</p>
<p>&#160;&#160;&#160; public void doExecute() {   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; jt = new JdbcTemplate(dataSource);    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; jt.execute(&quot;create table mytable (id integer, name varchar(100))&quot;);     <br />&#160;&#160;&#160; }</p>
<p>&#160;&#160;&#160; public void setDataSource(DataSource dataSource) {   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.dataSource = dataSource;    <br />&#160;&#160;&#160; }    <br />}</p>
<p>这个就是普通的 Java 类, 再参考 11.2.4. DataSource接口, 这里的另一个代码片断:   <br />DriverManagerDataSource dataSource = new DriverManagerDataSource();    <br />dataSource.setDriverClassName(&quot;org.hsqldb.jdbcDriver&quot;);    <br />dataSource.setUrl(&quot;jdbc:hsqldb:hsql://localhost:&quot;);    <br />dataSource.setUsername(&quot;sa&quot;);    <br />dataSource.setPassword(&quot;&quot;);</p>
<p>当然上面的连接方式可以配置成我们课程里面介绍的 MyEclipse Derby 的数据库连接:   <br />org.apache.derby.jdbc.ClientDriver    <br />jdbc:derby://localhost:1527/myeclipse;create=true    <br />app    <br />app</p>
<p>我们可以写一个测试类来执行代码:</p>
<p>import org.springframework.jdbc.datasource.DriverManagerDataSource;</p>
<p>public class TestTemplate {   <br />&#160; public static void main(String[] args) {    <br />&#160;&#160;&#160; // 新建一个数据源对象    <br />&#160;&#160;&#160; DriverManagerDataSource dataSource = new DriverManagerDataSource();    <br />&#160;&#160;&#160; dataSource.setDriverClassName(&quot;org.hsqldb.jdbcDriver&quot;);    <br />&#160;&#160;&#160; dataSource.setUrl(&quot;jdbc:hsqldb:hsql://localhost:&quot;);    <br />&#160;&#160;&#160; dataSource.setUsername(&quot;sa&quot;);    <br />&#160;&#160;&#160; dataSource.setPassword(&quot;&quot;);    <br />&#160;&#160;&#160; // 新建一个ExecuteAStatement 对象    <br />&#160;&#160;&#160; ExecuteAStatement eas = new ExecuteAStatement();    <br />&#160;&#160;&#160; // 给执行表达式的对象关联数据源(也就是常说的注入, 通过 JavaBean 的 setXxx 方法关联起来)    <br />&#160;&#160;&#160; eas.setDataSource(dataSource);    <br />&#160;&#160;&#160; // 执行功能代码    <br />&#160;&#160;&#160; eas.doExecute();    <br />&#160; }    <br />}</p>
<p>这个代码可以跑通, 就是普通的编程方式, 大家可以去看刚才介绍的文档附近的详细说明.</p>
<p>那么如果用 Spring 来做, 代码会变成这样:   <br />ExecuteAStatement 类代码保持不变, 多了个 beans.xml:    <br />&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;    <br />&lt;beans    <br /> xmlns=&quot;http://www.springframework.org/schema/beans&quot;    <br /> xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;    <br /> xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;</p>
<p> &lt;bean id=&quot;userDAO&quot; class=&quot;ExecuteAStatement&quot;&gt;   <br />&#160; &lt;property name=&quot;dataSource&quot;&gt;    <br />&#160;&#160; &lt;ref bean=&quot;myDataSource&quot; /&gt;    <br />&#160; &lt;/property&gt;    <br /> &lt;/bean&gt;</p>
<p> &lt;bean id=&quot;myDataSource&quot;   <br />&#160; class=&quot;org.springframework.jdbc.datasource.DriverManagerDataSource&quot;&gt;    <br />&#160; &lt;property name=&quot;driverClassName&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160; &lt;value&gt;org.hsqldb.jdbcDriver&lt;/value&gt;    <br />&#160; &lt;/property&gt;    <br />&#160; &lt;property name=&quot;url&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160; &lt;value&gt;jdbc:hsqldb:hsql://localhost:&lt;/value&gt;    <br />&#160; &lt;/property&gt;    <br />&#160; &lt;property name=&quot;username&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160; &lt;value&gt;sa&lt;/value&gt;    <br />&#160; &lt;/property&gt;    <br />&#160; &lt;property name=&quot;password&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160; &lt;value&gt;&lt;/value&gt;    <br />&#160; &lt;/property&gt;&#160;&#160;&#160;&#160;&#160;&#160; <br /> &lt;/bean&gt;</p>
<p>&lt;/beans&gt;</p>
<p>测试类:</p>
<p>import org.springframework.context.ApplicationContext;   <br />import org.springframework.context.support.ClassPathXmlApplicationContext;</p>
<p>public class Test {</p>
<p> public static void main(String[] args) throws IOException {   <br />&#160; ApplicationContext context = new ClassPathXmlApplicationContext(&quot;beans.xml&quot;);    <br />&#160; ExecuteAStatement eas =(ExecuteAStatement)context.getBean(&quot;userDAO&quot;);    <br />&#160;&#160;&#160;&#160;&#160; // 执行功能代码    <br />&#160;&#160;&#160;&#160;&#160; eas.doExecute();    <br /> }    <br />}</p>
<p>和上面的 TestTemplate 类相比, 就会发现 new DriverManagerDataSource() 这个过程不用我们写了, 运行的时候会发现一切都执行的好好的, 也就是常说的 ExecuteAStatement 的 dataSource 这个属性被注入了. </p>
<p>那么这个过程到底该如何理解呢? Spring 是一个对象池, 可以简化为一个 Map, 存多个主键和对象的映射. 那么 Spring 运行的过程中, 会根据 beans.xml 一步步进行必要的解析工作:</p>
<p>Map springEngine = new HashMap();</p>
<p>OK, 解析到了   <br />&lt;bean id=&quot;userDAO&quot; class=&quot;ExecuteAStatement&quot;&gt;, 发现 bean 定义, 那就新建一个实例存到对象池里吧, 主键就是 userDAO, 值就是对象:    <br />ExecuteAStatement bean1 = new ExecuteAStatement();    <br />springEngine.put(&quot;userDAO&quot;, bean1);</p>
<p>再往下执行, 发现 property 定义:   <br />&lt;property name=&quot;dataSource&quot;&gt;    <br />到了这里, 就知道应该调用 bean1.setDataSource(DataSource) 方法了. 可以接着执行, 发现    <br />&lt;ref bean=&quot;myDataSource&quot; /&gt;, 哦, 这个方法的参数还没有呢, 是个 bean 的引用, 好了, 要调用这个方法, 还是先 new 一个名字为 myDataSource 的 bean2 吧. 就跳到下面寻找 myDataSource 的定义, 找到了:    <br /> &lt;bean id=&quot;myDataSource&quot;    <br />&#160; class=&quot;org.springframework.jdbc.datasource.DriverManagerDataSource&quot;&gt;    <br />&#160; &lt;property name=&quot;driverClassName&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160; &lt;value&gt;org.hsqldb.jdbcDriver&lt;/value&gt;    <br />&#160; &lt;/property&gt;    <br />&#160; &lt;property name=&quot;url&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160; &lt;value&gt;jdbc:hsqldb:hsql://localhost:&lt;/value&gt;    <br />&#160; &lt;/property&gt;    <br />&#160; &lt;property name=&quot;username&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160; &lt;value&gt;sa&lt;/value&gt;    <br />&#160; &lt;/property&gt;    <br />&#160; &lt;property name=&quot;password&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160; &lt;value&gt;&lt;/value&gt;    <br />&#160; &lt;/property&gt;&#160;&#160;&#160;&#160;&#160;&#160; <br /> &lt;/bean&gt;    <br />像以前一样, 先实例化这个类, 然后看到 property 表情就调用对应的 setXxx() 这样的方法, 相当于下面一段代码:    <br />&#160;&#160;&#160; // 新建一个数据源对象    <br />&#160;&#160;&#160; DriverManagerDataSource bean2 = new DriverManagerDataSource();    <br />&#160;&#160;&#160; bean2.setDriverClassName(&quot;org.hsqldb.jdbcDriver&quot;);    <br />&#160;&#160;&#160; bean2.setUrl(&quot;jdbc:hsqldb:hsql://localhost:&quot;);    <br />&#160;&#160;&#160; bean2.setUsername(&quot;sa&quot;);    <br />&#160;&#160;&#160; bean2.setPassword(&quot;&quot;);    <br />不是还有个 bean 的 id 名字为 myDataSource 嘛, 那就把它存到对象池里面:</p>
<p>springEngine.put(&quot;myDataSource&quot;, bean2);</p>
<p>好了, 最后就是把他们两个关联起来了, 通过 ref 里指定的 bean id 名来关联起来:</p>
<p>// 省略类型转换的代码   <br />springEngine.get(&quot;userDAO&quot;).setDataSource(springEngine.get(&quot;myDataSource&quot;));</p>
<p>最后返回给用户的就是一个对象池(一个 Map)了, 所以别人调用的时候, 就发现 springEngine.get(&quot;userDAO&quot;) 回来的类的 dataSource 属性已经被实例化过了, 这些都是 Spring 幕后工作的代码, 通过反射机制来实现.</p>
<p>所以最后写代码调用:   <br />context.getBean(&quot;userDAO&quot;) 的时候, 得到的是 ExecuteAStatement, 这时候还有一个 myDataSource, 也可以被调用:    <br />context.getBean(&quot;myDataSource&quot;), 得到的是 DriverManagerDataSource.</p>
<p>介绍的过程, 仅供参考. 欢迎大家交流更好的原理介绍文章.</p>
<p>再转一篇别人推荐的通俗易懂的说明, 非实现方面的:</p>
<p>IoC就是Inversion of Control，控制反转。在Java开发中，IoC意味着将你设计好的类交给系统去控制，而不是在你的类内部控制。这称为控制反转。    <br />下面我们以几个例子来说明什么是IoC     <br />假设我们要设计一个Girl和一个Boy类，其中Girl有kiss方法，即Girl想要Kiss一个Boy。那么，我们的问题是，Girl如何能够认识这个Boy？     <br />在我们中国，常见的MM与GG的认识方式有以下几种     <br />1 青梅竹马； 2 亲友介绍； 3 父母包办     <br />那么哪一种才是最好呢？     <br />青梅竹马：Girl从小就知道自己的Boy。     <br />public class Girl {     <br />void kiss(){     <br />Boy boy = new Boy();     <br />}     <br />}     <br />然而从开始就创建的Boy缺点就是无法在更换。并且要负责Boy的整个生命周期。如果我们的Girl想要换一个怎么办？（严重不支持Girl经常更换Boy,#_#）     <br />亲友介绍：由中间人负责提供Boy来见面     <br />public class Girl {     <br />void kiss(){     <br />Boy boy = BoyFactory.createBoy();     <br />}     <br />}     <br />亲友介绍，固然是好。如果不满意，尽管另外换一个好了。但是，亲友BoyFactory经常是以Singleton的形式出现，不然就是，存在于 Globals，无处不在，无处不能。实在是太繁琐了一点，不够灵活。我为什么一定要这个亲友掺和进来呢？为什么一定要付给她介绍费呢？万一最好的朋友爱上了我的男朋友呢？     <br />父母包办：一切交给父母，自己不用费吹灰之力，只需要等着Kiss就好了。     <br />public class Girl {     <br />void kiss(Boy boy){     <br />// kiss boy     <br />boy.kiss();     <br />}     <br />}     <br />Well，这是对Girl最好的方法，只要想办法贿赂了Girl的父母，并把Boy交给他。那么我们就可以轻松的和Girl来Kiss了。看来几千年传统的父母之命还真是有用哦。至少Boy和Girl不用自己瞎忙乎了。     <br />这就是IOC，将对象的创建和获取提取到外部。由外部容器提供需要的组件。     <br />我们知道好莱坞原则：“Do not call us, we will call you.” 意思就是，You, girlie, do not call the boy. We will feed you a boy。     <br />我们还应该知道依赖倒转原则即 Dependence Inversion Princinple，DIP     <br />Eric Gamma说，要面向抽象编程。面向接口编程是面向对象的核心。     <br />组件应该分为两部分，即 Service, 所提供功能的声明 Implementation, Service的实现     <br />好处是：多实现可以任意切换，防止 “everything depends on everything” 问题．即具体依赖于具体。     <br />所以，我们的Boy应该是实现Kissable接口。这样一旦Girl不想kiss可恶的Boy的话，还可以kiss可爱的kitten和慈祥的grandmother。     <br />二、IOC的type     <br />IoC的Type指的是Girl得到Boy的几种不同方式。我们逐一来说明。     <br />IOC type 0：不用IOC     <br />public class Girl implements Servicable {     <br />private Kissable kissable;     <br />public Girl() {     <br />kissable = new Boy();     <br />}     <br />public void kissYourKissable() {     <br />kissable.kiss();     <br />}     <br />}     <br />Girl自己建立自己的Boy，很难更换，很难共享给别人，只能单独使用，并负责完全的生命周期。     <br />IOC type 1，先看代码：代码     <br />public class Girl implements Servicable {     <br />Kissable kissable;     <br />public void service(ServiceManager mgr) {     <br />kissable = (Kissable) mgr.lookup(“kissable”);     <br />}     <br />public void kissYourKissable() {     <br />kissable.kiss();     <br />}     <br />}     <br />这种情况出现于Avalon Framework。一个组件实现了Servicable接口，就必须实现service方法，并传入一个ServiceManager。其中会含有需要的其它组件。只需要在service方法中初始化需要的Boy。     <br />另外，J2EE中从Context取得对象也属于type 1。它依赖于配置文件。     <br />IOC type 2：     <br />public class Girl {     <br />private Kissable kissable;     <br />public void setKissable(Kissable kissable) {     <br />this.kissable = kissable;     <br />}     <br />public void kissYourKissable() {     <br />kissable.kiss();     <br />}     <br />}     <br />Type 2出现于Spring Framework，是通过JavaBean的set方法来将需要的Boy传递给Girl。它必须依赖于配置文件。     <br />IOC type 3:     <br />public class Girl {     <br />private Kissable kissable;     <br />public Girl(Kissable kissable) {     <br />this.kissable = kissable;     <br />}     <br />public void kissYourKissable() {     <br />kissable.kiss();     <br />}     <br />}     <br />这就是PicoContainer的组件 。通过构造函数传递Boy给Girl     <br />PicoContainer container = new DefaultPicoContainer();     <br />container.registerComponentImplementation(Boy.class);     <br />container.registerComponentImplementation(Girl.class);     <br />Girl girl = (Girl) container.getComponentInstance(Girl.class);     <br />girl.kissYourKissable();     <br />参考资料     <br />1 http://www.picocontainer.org/presentations/JavaPolis2003.ppt    <br />http://www.picocontainer.org/presentations/JavaPolis2003.pdf    <br />2 DIP， Robert C Martin, Bob大叔的优秀论文     <br />http://www.objectmentor.com/resources/articles/dip.pdf    <br />3 Dependency Injection 依赖注射，Matrin Fowler对DIP的扩展     <br />http://www.martinfowler.com/articles/injection.html    <br />4 IOC框架     <br />PicoContainer 优秀的IOC框架     <br />http://picocontainer.org/    <br />Avalon     <br />http://avalon.apache.org/    <br />Spring Framework     <br />http://www.springframework.org/    <br />HiveMind     <br />http://jakarta.apache.org/commons/hivemind    <br />&#8212;-    <br />IoC是一种模式     <br />IoC(Inversion of Control)中文译为控制反转，目前Java社群中流行的各种轻量级容器的实现都是以IoC模式作为基础的。控制反转意味着在系统开发过程中，设计的类将交由容器去控制，而不是在类的内部去控制，类与类之间的关系将交由容器处理,一个类在需要调用另一个类时,只要调用另一个类在容器中注册的名字就可以得到这个类的实例,与传统的编程方式有了很大的不同,”不用你找,我来提供给你”,这就是控制反转的含义。Martin Fowler在他的一篇文章中给IoC起了一个更为直观的名字：依赖注射DI(Dependency Injection)。下面先引入这个模式。     <br />在设计模式中，我们已经习惯一种思维编程方式：Interface Driven Design 接口驱动，接口驱动有很多好处，可以提供不同灵活的子类实现，增加代码稳定和健壮性等等，但是接口一定是需要实现的，也就是如下语句迟早要执行：     <br />InterfaceA a = new InterfaceAImp()；     <br />InterfaceAImp 是接口InterfaceA的一个子类，IoC模式可以延缓接口的实现，根据需要实现，有个比喻：接口如同空的模型套，在必要时，需要向模型套注射石膏，这样才能成为一个模型实体，因此，我们将人为控制接口的实现成为注射。IoC模式是解决调用者和被调用者之间的一种关系，上述InterfaceA实现语句表明当前是在调用被调用者InterfaceAImp，由于被调用者名称写入了调用者的代码中，这产生了一个接口实现的原罪：彼此联系，调用者和被调用者有紧密联系，在UML中是用依赖 Dependency 表示。但是这种依赖在分离关注的思维下是不可忍耐的，必须切割，实现调用者和被调用者解耦，新的Ioc模式依赖注射 (Dependency Injection)模式由此产生了，也就是将依赖先剥离，然后在适当时候再注射进入。 </p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-ioc-yuanli-234/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IOC 后台机制学习&#8211;转</title>
		<link>http://javadou.com/ioc-study-233/</link>
		<comments>http://javadou.com/ioc-study-233/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 18:26:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[ioc]]></category>

		<guid isPermaLink="false">http://javadou.com/ioc-study-233/</guid>
		<description><![CDATA[题目: IOC 后台机制学习 
给定: 
配置文件 config.txt, 文件内容 
className = test.JavaBean1 
field = username 
value = ABC 
该文件中的三个值会随时可能变化, 唯一不变的是 className 指定的都是一个 JavaBean(为了简化, 我们假定里面已经... ]]></description>
			<content:encoded><![CDATA[<p>转自beansoft</p>
<p>题目: IOC 后台机制学习    <br />给定:     <br />配置文件 config.txt, 文件内容     <br />className = test.JavaBean1     <br />field = username     <br />value = ABC     <br />该文件中的三个值会随时可能变化, 唯一不变的是 className 指定的都是一个 JavaBean(为了简化, 我们假定里面已经有一个 username 属性, 例如:     <br />class JavaBeanxxxx {     <br />&#160;&#160;&#160; private String username;     <br />&#160;&#160;&#160; public String getUsername() {     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; return username;     <br />&#160;&#160;&#160; }     <br />&#160;&#160;&#160; public void setUsername(String uname) {     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.username = uname;     <br />&#160;&#160;&#160; }     <br />}     <br />要求: 写一段代码, 读取配置文件 config.txt, 然后实现把 className 指定的 JavaBean 类加载(注意这个类名是可以修改的, 可配置的), 然后生成一个实例,     <br />并把配置文件中field字段指定的值作为这个实例的属性名(这里是username)所对应的值设置为 ABC(字符串), 并且要读出最后设置的值.     <br />此题已经被 TigerTian 解答出来, 欢迎学习, 也感谢 TigerTian:</p>
<pre class="java">

package com.gcoresoft.ioc;import java.io.*;import java.lang.reflect.*;import java.util.*;import java.beans.*;public class IOCStudy {//Load the properties fileprivate Properties prop=new Properties();public void loadPropFile(String filename)&#160;&#160;&#160; {try&#160;&#160;&#160;&#160;&#160;&#160;&#160; {&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; FileInputStream fin=new FileInputStream(filename);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; prop.load(fin);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; fin.close();&#160;&#160;&#160;&#160;&#160;&#160;&#160; }catch(Exception e){&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println(e.toString());&#160;&#160;&#160;&#160;&#160;&#160;&#160; }&#160;&#160;&#160; }private String getValueByName(String Name)&#160;&#160;&#160; {return prop.getProperty(Name);&#160;&#160;&#160; }public static void main(String[] args)&#160;&#160;&#160; {&#160;&#160;&#160;&#160;&#160;&#160;&#160; IOCStudy ioc=new IOCStudy();&#160;&#160;&#160;&#160;&#160;&#160;&#160; ioc.loadPropFile(&quot;E:\\Work\\GetInIOC\\src\\com\\gcoresoft\\ioc\\Config.txt&quot;);try&#160;&#160;&#160;&#160;&#160;&#160;&#160; {&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Class bean=Class.forName(ioc.getValueByName(&quot;className&quot;));try {&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; java.beans.BeanInfo info=java.beans.Introspector.getBeanInfo(bean);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; java.beans.PropertyDescriptor pd[]=info.getPropertyDescriptors();try {&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Method mSet=null,mRead=null;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Object obj=bean.newInstance();for(int i=0;i&lt;pd.length;i++)if(pd[i].getName().equalsIgnoreCase(ioc.getValueByName(&quot;field&quot;)))&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; mSet=pd[i].getWriteMethod();&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; mRead=pd[i].getReadMethod();&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }try {&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; mSet.invoke(obj, ioc.getValueByName(&quot;value&quot;));&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String str=(String)mRead.invoke(obj, null);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println(str);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } catch (IllegalArgumentException e) {// TODO Auto-generated catch block&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; e.printStackTrace();&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } catch (InvocationTargetException e) {// TODO Auto-generated catch block&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; e.printStackTrace();&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } catch (InstantiationException e) {// TODO Auto-generated catch block&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; e.printStackTrace();&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } catch (IllegalAccessException e) {// TODO Auto-generated catch block&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; e.printStackTrace();&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; } catch (IntrospectionException e) {// TODO Auto-generated catch block&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; e.printStackTrace();&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }&#160;&#160;&#160;&#160;&#160;&#160;&#160; }catch(ClassNotFoundException e){&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println(e.toString());&#160;&#160;&#160;&#160;&#160;&#160;&#160; }&#160;&#160;&#160; }}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/ioc-study-233/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring 2.5 annotation标注开发的简单例子</title>
		<link>http://javadou.com/spring25-annotation-demo-228/</link>
		<comments>http://javadou.com/spring25-annotation-demo-228/#comments</comments>
		<pubDate>Sun, 06 Sep 2009 06:18:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[annotation]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring25-annotation-demo-228/</guid>
		<description><![CDATA[研究了很久新出的 Spring 2.5, 总算大致明白了如何用标注定义 Bean, 但是如何定义和注入类型为 java.lang.String 的 bean 仍然未解决, 希望得到高人帮助.

总的来看 Java EE 5 的标注开发方式开来是得到了大家的认可了.

Service... ]]></description>
			<content:encoded><![CDATA[<p>研究了很久新出的 Spring 2.5, 总算大致明白了如何用标注定义 Bean, 但是如何定义和注入类型为 java.lang.String 的 bean 仍然未解决, 希望得到高人帮助.</p>
<p>总的来看 Java EE 5 的标注开发方式开来是得到了大家的认可了.</p>
<p>@Service 相当于定义 bean, 自动根据 bean 的类名生成一个首字母小写的 bean</p>
<p>@Autowired 则是自动注入依赖的类, 它会在类路径中找成员对应的类/接口的实现类, 如果找到多个, 需要用 @Qualifier(&quot;chineseMan&quot;) 来指定对应的 bean 的 ID.</p>
<p>一定程度上大大简化了代码的编写, 例如一对一的 bean 映射现在完全不需要写任何额外的 bean 定义了.</p>
<p>下面是代码的运行结果:</p>
<p>man.sayHello()=抽你丫的    <br />SimpleMan said: Hi     <br />org.example.EnglishMan@12bcd4b said: Fuck you! </p>
<p>代码:</p>
<p>beans.xml</p>
<pre class="xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
       xsi:schemaLocation=&quot;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&quot;&gt;

     &lt;context:annotation-config/&gt;
     &lt;context:component-scan base-package=&quot;org.example&quot;/&gt;

&lt;/beans&gt;</pre>
<pre class="java">import org.example.IMan;
import org.example.SimpleMan;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(&quot;beans.xml&quot;);
        SimpleMan dao = (SimpleMan) ctx.getBean(&quot;simpleMan&quot;);
        System.out.println(dao.hello());
        IMan man = (IMan) ctx.getBean(&quot;usMan&quot;);
        System.out.println(man.sayHello());
    }
}

自动探测和注入bean的类:

package org.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class SimpleMan {
    // 自动注入名称为 Man 的 Bean
    @Autowired(required = false)
    @Qualifier(&quot;chineseMan&quot;)
    //@Qualifier(&quot;usMan&quot;)
    private IMan man;   

    /**
     * @return the man
     */
    public IMan getMan() {
        return man;
    }

    /**
     * @param man the man to set
     */
    public void setMan(IMan man) {
        this.man = man;
    }

    public String hello() {
        System.out.println(&quot;man.sayHello()=&quot; + man.sayHello());
        return &quot;SimpleMan said: Hi&quot;;
    }
}

一个接口和两个实现类:

package org.example;

/**
* 抽象的人接口.
* @author BeanSoft
* @version 1.0
*/
public interface IMan {
    /**
     * 打招呼的抽象定义.
     * @return 招呼的内容字符串
     */
    public String sayHello();
}

package org.example;

import org.springframework.stereotype.Service;

/**
* 中国人的实现.
* @author BeanSoft
*/
@Service
public class ChineseMan implements IMan {

    public String sayHello() {
        return &quot;抽你丫的&quot;;
    }

}

package org.example;

import org.springframework.stereotype.Service;

/**
* @author BeanSoft
* 美国大兵
*/
@Service(&quot;usMan&quot;)
// 这里定义了一个 id 为 usMan 的 Bean, 标注里面的属性是 bean 的 id
public class EnglishMan implements IMan {

    public String sayHello() {
        return this + &quot; said: Fuck you!&quot;;
    }

} </pre>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring25-annotation-demo-228/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IBM 中文网站的 Spring 系列等资料</title>
		<link>http://javadou.com/ibm-site-spring-ziliao-227/</link>
		<comments>http://javadou.com/ibm-site-spring-ziliao-227/#comments</comments>
		<pubDate>Sun, 06 Sep 2009 04:17:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/ibm-site-spring-ziliao-227/</guid>
		<description><![CDATA[翻译: MyEclipse Spring 入门教程(含官方视频和AOP例子) http://www.blogjava.net/beansoft/archive/2007/11/27/163416.html 使用 HibernateTemplate 实现分页查询 http://www.blogjava.net/beansoft/archive/2007/10/10/151702.html 转载: Eclipse插件之Spring IDE http://www... ]]></description>
			<content:encoded><![CDATA[<p>翻译: MyEclipse Spring 入门教程(含官方视频和AOP例子) <a href="http://www.blogjava.net/beansoft/archive/2007/11/27/163416.html">http://www.blogjava.net/beansoft/archive/2007/11/27/163416.html</a></p>
<p>使用 HibernateTemplate 实现分页查询 <a href="http://www.blogjava.net/beansoft/archive/2007/10/10/151702.html">http://www.blogjava.net/beansoft/archive/2007/10/10/151702.html</a></p>
<p>转载: Eclipse插件之Spring IDE <a href="http://www.blogjava.net/beansoft/archive/2007/10/02/150127.html">http://www.blogjava.net/beansoft/archive/2007/10/02/150127.html</a></p>
<p><b>IBM </b><b>开发网站的Spring</b><b>系列（含代码）：</b></p>
<p><a href="http://www-128.ibm.com/developerworks/cn/java/wa-spring1/">http://www-128.ibm.com/developerworks/cn/java/wa-spring1/</a> Spring 系列: Spring 框架简介――Spring AOP 和 IOC 容器入门 </p>
<p><a href="http://www-128.ibm.com/developerworks/cn/java/wa-spring2/">http://www-128.ibm.com/developerworks/cn/java/wa-spring2/</a> Spring 系列，第 2 部分: 当 Hibernate 遇上 Spring――Hibernate 事务天生适合 Spring AOP </p>
<p><a href="http://www-128.ibm.com/developerworks/cn/java/wa-spring3/">http://www-128.ibm.com/developerworks/cn/java/wa-spring3/</a> Spring 系列，第 3 部分: 进入 Spring MVC――用 Spring MVC 轻松进行应用程序开发 </p>
<p><a href="http://www-128.ibm.com/developerworks/cn/java/wa-spring4/">http://www-128.ibm.com/developerworks/cn/java/wa-spring4/</a> Spring 系列，第 4 部分: Spring JMS 消息处理 1-2-3――Spring JMS 把企业消息处理变得轻而易举 </p>
<p>来自满江红开源网站（<a href="http://wiki.redsaga.com/confluence/display/RSTEAM/Home">http://wiki.redsaga.com/confluence/display/RSTEAM/Home</a>）的中文文档： </p>
<p>《Spring 开发指南》 作者：Xiaxin (夏昕) PDF 格式169页, 1.02M 下载地址：<a href="http://www.xiaxin.net/Spring_Dev_Guide.rar">http://www.xiaxin.net/Spring_Dev_Guide.rar</a></p>
<p>SpringFramework概述 翻译：DigitalSonic PDF 格式 24 页，322K 下载地址： </p>
<p><a href="http://www.redsaga.com/opendoc/OpenDoc-IntroduceToSpringFramework.pdf">http://www.redsaga.com/opendoc/OpenDoc-IntroduceToSpringFramework.pdf</a></p>
<p>Spring 2.0 Reference（官方参考手册） 翻译：DigitalSonic 2006/10/22 完成 HTML版本地址：<a href="http://www.redsaga.com/opendoc/Seam2.0/html">http://www.redsaga.com/opendoc/Seam2.0/html</a> PDF版本(509页, 3.74M) 下载地址：<a href="http://download.gro.clinux.org/jaction/spring2.0-reference_final_zh_cn.pdf">http://download.gro.clinux.org/jaction/spring2.0-reference_final_zh_cn.pdf</a> ,CHM版本(2.2M)下载地址：<a href="https://gro.clinux.org/frs/download.php/1828/spring2.0-reference_final_zh_cn.chm">https://gro.clinux.org/frs/download.php/1828/spring2.0-reference_final_zh_cn.chm</a></p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/ibm-site-spring-ziliao-227/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenSessionInViewFilter 的两个异常</title>
		<link>http://javadou.com/spring-opensessioninviewfilter-226/</link>
		<comments>http://javadou.com/spring-opensessioninviewfilter-226/#comments</comments>
		<pubDate>Sun, 06 Sep 2009 02:15:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[OpenSessionInViewFilter]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-opensessioninviewfilter-226/</guid>
		<description><![CDATA[OpenSessionInViewFilter 的两个异常:Illegal attempt to associate a collection with two open sessions; Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL) 
使用 Spring 整合 Hibernate, 在懒加载的情况下, 有时候需要在 JSP/View 层显示数据... ]]></description>
			<content:encoded><![CDATA[<p>&#160;&#160; OpenSessionInViewFilter 的两个异常:Illegal attempt to associate a collection with two open sessions; Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL)    <br />使用 Spring 整合 Hibernate, 在懒加载的情况下, 有时候需要在 JSP/View 层显示数据, 这时候就要用到Spring内置的: OpenSessionInViewFilter, 一般来说配置如下(web.xml):     </p>
<pre class="xml">&lt;filter&gt;&lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.springframework.orm.hibernate3.support.OpenSessionInViewFilter&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;singleSession&lt;/param-name&gt;&lt;param-value&gt;true&lt;/param-value&gt;&lt;/init-param&gt;&lt;!-- 和 spring 中的sesssionfactory ID 一致 –&gt;&lt;init-param&gt;&lt;param-name&gt;sessionFactoryBeanName&lt;/param-name&gt;&lt;param-value&gt;sessionFactory&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt;&lt;url-pattern&gt;*.do&lt;/url-pattern&gt;&lt;!-- *.jsp, *.do--&gt;&lt;/filter-mapping&gt;</pre>
<p>不过, 这时候又会导致更新数据时抛出如下异常:</p>
<p>Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove &#8216;readOnly&#8217; marker from transaction definiti<br />
  <br />这时候再去网上找解决方案, 会有人说: 把参数 singleSession改为false, 就行了. 不过, 改完后, 估计不久就会遇到另一个郁闷的异常: </p>
<p>org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions </p>
<p></p>
<p>这下完了, 两个方案都不行, 到底怎么办? 还好, 在<a href="http://xuliangyong.javaeye.com/blog/144818">http://xuliangyong.javaeye.com/blog/144818</a>的主页上, 给了一个方案, 就是改写 OpenSessionInViewFilter 的代码, 非常感谢, 下面给出的就是最终方案: </p>
<p>web.xml </p>
<pre class="xml">&lt; filter-name &gt;hibernateFilter&lt;/filter-name&gt;


&lt; filter-class &gt; org.springframework.orm.hibernate3.support.OurOpenSessionInViewFilter &lt;/filter-class&gt;
</pre>
<p>OurOpenSessionInViewFilter.java 代码:<br />
  </p>
<pre class="java">package org.springframework.orm.hibernate3.support;

import org.hibernate.*;

/** * 单session模式下, 默认会发生无法提交的错误: * Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition. * 需要设置FlushMode并刷新session. * 参考: http://xuliangyong.javaeye.com/blog/144818 * @author 刘长炯 */publicclass OurOpenSessionInViewFilter extends OpenSessionInViewFilter {

    public OurOpenSessionInViewFilter() {
        super.setFlushMode(FlushMode.AUTO);
    }

    protectedvoid closeSession(Session session, SessionFactory sessionFactory) {
        session.flush();

        try {
            session.getTransaction().commit();
        } catch (HibernateException e) {
            // TODO Auto-generated catch block//e.printStackTrace();
        }

        super.closeSession(session, sessionFactory);
    }
}</pre>
<p>如果各位有更好的解决方案, 欢迎讨论哦!!!</p>
<p>题外话:</p>
<p>感觉 Spring + Hibernate 的健壮性还是不够啊! 容易抛异常, 这是事实, 也许这是开源软件的通病吧.</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-opensessioninviewfilter-226/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>spring+hibernate避免延迟加载异常OpenSessionInViewFilter(no session)</title>
		<link>http://javadou.com/spring-hibernate-opensessioninviewfilter-211/</link>
		<comments>http://javadou.com/spring-hibernate-opensessioninviewfilter-211/#comments</comments>
		<pubDate>Sat, 05 Sep 2009 08:09:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[OpenSessionInViewFilter]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-hibernate-opensessioninviewfilter-211/</guid>
		<description><![CDATA[在hibernate中，延迟加载是1个非常大的优点，但有时候却给我们带来一些小麻烦，在后台查询结束后，session已经关闭，但在前台显示的时候，如果存在关联关系就会产生延迟加载异常。 
解决办法是客户端每次请求就... ]]></description>
			<content:encoded><![CDATA[<p>&#160;&#160;&#160;&#160;&#160; 在hibernate中，延迟加载是1个非常大的优点，但有时候却给我们带来一些小麻烦，在后台查询结束后，session已经关闭，但在前台显示的时候，如果存在关联关系就会产生延迟加载异常。    <br />解决办法是客户端每次请求就分配1个session,将请求结果返回给客户端，并完成展现后关闭session。     <br />实现这个功能非常简单，在web.xml中加入以下配置</p>
<pre class="xml">&lt;filter&gt;
  &#160;&#160;&#160;&#160;&#160; &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;filter-class&gt;org.springframework.orm.hibernate3.support.OpenSessionInViewFilter &lt;/filter-class&gt;

&#160;&#160;&#160;&#160;&#160; &lt;init-param&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;param-name&gt;singleSession&lt;/param-name&gt;

&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;param-value&gt;true&lt;/param-value&gt;

&#160;&#160;&#160;&#160;&#160; &lt;/init-param&gt;

&lt;/filter&gt;

&lt;filter-mapping&gt;

&#160;&#160;&#160;&#160;&#160; &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt;

&#160;&#160;&#160;&#160;&#160; &lt;url-pattern&gt;*.do&lt;/url-pattern&gt;

&#160; &lt;/filter-mapping&gt;</pre>
<p>使用spring提供这个过滤器就可以实现session的集中管理了，所有以.do结尾的请求都自动分配了1个session,并且在这个请求过程中都使用这个session.</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-hibernate-opensessioninviewfilter-211/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>spring简化配置给spring减肥</title>
		<link>http://javadou.com/spring-easy-config-198/</link>
		<comments>http://javadou.com/spring-easy-config-198/#comments</comments>
		<pubDate>Fri, 04 Sep 2009 00:59:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[recommend]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-easy-config-198/</guid>
		<description><![CDATA[spring的配置文件是十分灵活的,比如当遇到要配置JDBC之类或者和主机有关的信息时，可以这样，进一步抽象 
生成如下的属性文件（/WEB-INF/jdbc.properties）： 
jdbc.driver=org.postgresql.Driver 
jdbc.url=jdbc:postgresql://localhost/test 
jd... ]]></description>
			<content:encoded><![CDATA[<p>spring的配置文件是十分灵活的,比如当遇到要配置JDBC之类或者和主机有关的信息时，可以这样，进一步抽象    <br />生成如下的属性文件（/WEB-INF/jdbc.properties）：     <br />jdbc.driver=org.postgresql.Driver     <br />jdbc.url=jdbc:postgresql://localhost/test     <br />jdbc.user=postgres     <br />jdbc.password=1234</p>
<p>我们的Bean配置如下：</p>
<pre class="xml">&lt;bean id=&quot;propertyConfigurer&quot;
  class=&quot;org.springframework.beans.factory.config.PropertyPlaceholderConfigurer&quot;&gt;

&lt;property name=&quot;location&quot;&gt;

&lt;value&gt;/WEB-INF/jdbc.properties&lt;/value&gt;

&lt;/property&gt;

&lt;/bean&gt;

&lt;bean id=&quot;dataSource&quot;

class=&quot;org.springframework.jdbc.datasource.DriverManagerDataSource&quot;&gt;

&lt;property name=&quot;driverClassName&quot;&gt;

&lt;value&gt;${jdbc.driver}&lt;/value&gt;

&lt;/property&gt;

&lt;property name=&quot;url&quot;&gt;

&lt;value&gt;${jdbc.url}&lt;/value&gt;

&lt;/property&gt;

&lt;property name=&quot;username&quot;&gt;

&lt;value&gt;${jdbc.user}&lt;/value&gt;

&lt;/property&gt;

&lt;property name=&quot;password&quot;&gt;

&lt;value&gt;${jdbc.password}&lt;/value&gt;

&lt;/property&gt;

&lt;/bean&gt;</pre>
<p>如上所述，我们定义了一个PropertyPlaceholderConfigurer类的实例，并将其位置属性设置为我们的属性文件。该类被实现为Bean工厂的后处理器，并将使用定义在文件中的属性来代替所有的占位符（${&#8230;}value）。</p>
<p>利用这种技术，我们可以从applicationContext.xml中移除所有特定于主机的配置属性。通过这种方式，我们可以自由地为该文件添加新的Bean，而不必担心特定于主机属性的同步性。这样可以简化生产部署和维护</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-easy-config-198/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Spring：IoC，AOP学习</title>
		<link>http://javadou.com/spring-ioc-aop-195/</link>
		<comments>http://javadou.com/spring-ioc-aop-195/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 19:38:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[aop]]></category>
		<category><![CDATA[ioc]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-ioc-aop-195/</guid>
		<description><![CDATA[1 从http://www.springframework.org下载Spring 
2 用eclipse新建Java项目 
3 建立我们的业务方法接... ]]></description>
			<content:encoded><![CDATA[<p>1 从http://www.springframework.org下载Spring    <br />2 用eclipse新建Java项目     <br />3 建立我们的业务方法接口</p>
<pre class="java">public interface BusinessObject {
  public void doSomething();

public void doAnotherThing();

}</pre>
<p>4 实现业务方法，注意这是的setWords使用了依赖注入，所谓依赖注入就是把配置文件中的字符串什么的在程序运行时“自动”放到我们的程序中来。如果不是这样，我们就只能在代码中固化这些东西，从而违背了面向对象的依赖倒置原则，还有一种满足依赖倒置的方法，即依赖查询，这就是所谓的factory模式，即在代码中请求某种抽象的东西，然后根据配置得到它，但这种办法向对于依赖注入多了对环境的依赖，且代码冗余，EJB的JNDI查询就属于这种。另外我们的Spring配置文件是以bean为核心的，就是我们写的一个类，在XML中描述它的名称、位置和涵盖的内容、关系。</p>
<pre class="java">public class BusinessObjectImpl implements BusinessObject {
  private String words;

public void setWords(String words){

this.words = words;

&#160;&#160;&#160; }

public void doSomething() {

&#160;&#160;&#160;&#160;&#160;&#160;&#160; Log log = LogFactory.getLog(this.getClass());

&#160;&#160;&#160;&#160;&#160;&#160;&#160; log.info(words);

&#160;&#160;&#160; }

public void doAnotherThing() {

&#160;&#160;&#160;&#160;&#160;&#160;&#160; Log log = LogFactory.getLog(this.getClass());

&#160;&#160;&#160;&#160;&#160;&#160;&#160; log.info(&quot;Another thing&quot;);

&#160;&#160;&#160; }

}</pre>
<p>5 建立一个运行方法类，从配置文件spring-beans.xml中读入bo这个类的定义，然后实例化一个对象</p>
<pre class="java">import org.springframework.beans.factory.xml.XmlBeanFactory;
  import org.springframework.core.io.ClassPathResource;

public class Main {

public static void main(String[] args){

&#160;&#160;&#160;&#160;&#160;&#160;&#160; XmlBeanFactory xbf = new XmlBeanFactory(new ClassPathResource(&quot;spring-beans.xml&quot;));

&#160;&#160;&#160;&#160;&#160;&#160;&#160; BusinessObject bo = (BusinessObject)xbf.getBean(&quot;bo&quot;);

&#160;&#160;&#160;&#160;&#160;&#160;&#160; bo.doSomething();

&#160;&#160;&#160;&#160;&#160;&#160;&#160; bo.doAnotherThing();

&#160;&#160;&#160; }

}</pre>
<p>6 建立一个拦截器类invoke是MethodInterceptor必须实现的方法，表示拦截时的动作，大家仔细体会代码中的含义</p>
<pre class="java">import org.aopalliance.intercept.MethodInterceptor;
  import org.aopalliance.intercept.MethodInvocation;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

public class MyInterceptor implements MethodInterceptor {

private String before, after;

public void setAfter(String after) {

this.after = after;

&#160;&#160;&#160; }

public void setBefore(String before) {

this.before = before;

&#160;&#160;&#160; }

public Object invoke(MethodInvocation invocation) throws Throwable {

&#160;&#160;&#160;&#160;&#160;&#160;&#160; Log log = LogFactory.getLog(this.getClass());

&#160;&#160;&#160;&#160;&#160;&#160;&#160; log.info(before);

&#160;&#160;&#160;&#160;&#160;&#160;&#160; Object rval = invocation.proceed();

&#160;&#160;&#160;&#160;&#160;&#160;&#160; log.info(after);

return rval;

&#160;&#160;&#160; }

}</pre>
<p>7 建立配置文件组织上面的类之间的关系，AOP有切入点和增强这两个重要的概念，把两个概念结合到一起，就是一个在某个方法执行的时候附加执行，切入点表示在哪里附加，增强表示附加什么，配置文件中的myPointcut表示切入点，myInterceptor表示增强的内容，myAdvisor表示增强器，即两者的结合，在bo这个bean中，我们把这个增强器附加到了bo这个bean上。</p>
<pre class="xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
  &lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;

&lt;beans&gt;

&lt;bean id=&quot;businessObjectImpl&quot; class=&quot;BusinessObjectImpl&quot;&gt;

&lt;property name=&quot;words&quot;&gt;

&lt;value&gt;正在执行业务方法&lt;/value&gt;

&lt;/property&gt;

&lt;/bean&gt;

&lt;bean id=&quot;myInterceptor&quot; class=&quot;MyInterceptor&quot;&gt;

&lt;property name=&quot;before&quot;&gt;

&lt;value&gt;执行业务方法前&lt;/value&gt;

&lt;/property&gt;

&lt;property name=&quot;after&quot;&gt;

&lt;value&gt;执行业务方法后&lt;/value&gt;

&lt;/property&gt;

&lt;/bean&gt;

&lt;bean id=&quot;myPointcut&quot; class=&quot;org.springframework.aop.support.JdkRegexpMethodPointcut&quot;&gt;

&lt;property name=&quot;patterns&quot;&gt;

&lt;list&gt;

&lt;value&gt;BusinessObject.doSomething&lt;/value&gt;

&lt;/list&gt;

&lt;/property&gt;

&lt;/bean&gt;

&lt;bean id=&quot;myAdvisor&quot; class=&quot;org.springframework.aop.support.DefaultPointcutAdvisor&quot;&gt;

&lt;property name=&quot;pointcut&quot; ref=&quot;myPointcut&quot;/&gt;

&lt;property name=&quot;advice&quot; ref=&quot;myInterceptor&quot;/&gt;

&lt;/bean&gt;

&lt;bean id=&quot;bo&quot; class=&quot;org.springframework.aop.framework.ProxyFactoryBean&quot;&gt;

&lt;property name=&quot;target&quot;&gt;

&lt;ref local=&quot;businessObjectImpl&quot;/&gt;

&lt;/property&gt;

&lt;property name=&quot;proxyInterfaces&quot;&gt;

&lt;value&gt;BusinessObject&lt;/value&gt;

&lt;/property&gt;

&lt;property name=&quot;interceptorNames&quot;&gt;

&lt;list&gt;

&lt;value&gt;myInterceptor&lt;/value&gt;

&lt;value&gt;myAdvisor&lt;/value&gt;

&lt;/list&gt;

&lt;/property&gt;

&lt;/bean&gt;

&lt;/beans&gt;</pre>
<p>8 运行Main类，观察控制台输出结果，重新审查代码，反思为什么会出现这种结果。</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-ioc-aop-195/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring中使用Security2 实现动态角色权限</title>
		<link>http://javadou.com/spring-security2-role-193/</link>
		<comments>http://javadou.com/spring-security2-role-193/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 16:13:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-security2-role-193/</guid>
		<description><![CDATA[安全框架的主体包括两部分即验权和授权。Spring Security2可以很好的实现这两个过程。Spring Security2对其前身acegi最大的改进是提供了自定义的配置标签，通过Security的命名空间定义了http和authentication-provider等标签，这... ]]></description>
			<content:encoded><![CDATA[<p>&#160;&#160;&#160;&#160; 安全框架的主体包括两部分即验权和授权。Spring Security2可以很好的实现这两个过程。Spring Security2对其前身acegi最大的改进是提供了自定义的配置标签，通过Security的命名空间定义了http和authentication-provider等标签，这样做的好处是极大地简化了框架的配置，并很好地隐藏了框架实现的细节，在配置的表述上也更清晰，总体上提高了框架的易用性。</p>
<p>&#160;&#160;&#160;&#160; 然而，该框架默认的权限配置方式在xml中，又因为新版本隐藏了实现细节，在动态权限的扩展上，能力变小了。在验权过程中，遇到的问题不多。但在授权时，如果是acegi，人们可以通过继承AbstractFilterInvocationDefinitionSource类实现在授权（即资源角色和用户角色的匹配）前，针对资源的角色的获取。而新版本因为用新标签进行了整合，这个过程被默认的类实现隐藏掉了，包括过滤器，资源获取和角色定义等过程都由框架来实现，于是很多人在使用Spring Security2时也想通过改动DefaultFilterInvocationDefinitionSource对资源的获取来实现数据库或文件中的动态的角色。不过这样的改动侵入性比较高，而且还保留了acegi的痕迹，也违背了开闭的原则。</p>
<p>&#160;&#160;&#160;&#160; 其实，我们完全可以通过Spring Security2 accessManager提供的自定义投票机制来解决这个问题，这样既不影响现有的基于URL的配置，还可以加入自己的动态的权限配置。</p>
<p>其实现策略如下：</p>
<p>1 定义类DynamicRoleVoter实现AccessDecisionVoter，注入实现接口DynamicRoleProvider（用来定义获取角色的方法）的提供动态角色的类</p>
<p>2 在两个supports方法中返回true</p>
<p>3 在vote方法中，有三个参数(Authentication authentication, Object object,</p>
<p>ConfigAttributeDefinition config) 通过第一个获取用户的权限集合，第二个可以获取到资源对象，进而通过DynamicRoleProvider获取到角色集合进行匹配。</p>
<p>4 在配置文件中加入DynamicRoleVoter，如下：    </p>
<pre class="xml">&lt;beans:bean id=&quot;accessDecisionManager&quot; class=&quot;org.springframework.security.vote.AffirmativeBased&quot;&gt;
  <img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&lt;beans:property name=&quot;decisionVoters&quot;&gt;

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&lt;beans:list&gt;

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&lt;beans:bean class=&quot;org.springframework.security.vote.RoleVoter&quot; /&gt;

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&lt;beans:bean class=&quot;org.springframework.security.vote.AuthenticatedVoter&quot; /&gt;

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&lt;beans:bean class=&quot;DynamicRoleVoter&quot;&gt;

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /> &lt;beans:property name=&quot;dynamicRoleProvider&quot;&gt;

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /> &lt;beans:ref local=&quot;dynamicRoleProvider&quot;/&gt;

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&lt;/beans:property&gt;

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&lt;/beans:bean&gt;

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&lt;/beans:list&gt;

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&lt;/beans:property&gt;

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&lt;/beans:bean&gt;

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&lt;beans:bean id=” dynamicRoleProvider” class=”…”&gt;

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" /> ……

<img alt="" src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" />&lt;/beans:bean&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-security2-role-193/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring hibernate使用方法整理@Component(五)</title>
		<link>http://javadou.com/spring-jpa-hibernate-five-180/</link>
		<comments>http://javadou.com/spring-jpa-hibernate-five-180/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 10:31:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-jpa-hibernate-five-180/</guid>
		<description><![CDATA[虽然我们可以通过 Autowired 在 Bean 类中使用自动注入功能，但是 Bean 还是在 applicatonContext.xml 文件中通过  进行定义 —— 在前面的例子中，我们还是在配置文件中定义 Bean，通过 Autowired为 Bean 的成员变量、方法... ]]></description>
			<content:encoded><![CDATA[<p>虽然我们可以通过 @Autowired 在 Bean 类中使用自动注入功能，但是 Bean 还是在 applicatonContext.xml 文件中通过 &lt;bean&gt; 进行定义 —— 在前面的例子中，我们还是在配置文件中定义 Bean，通过 @Autowired为 Bean 的成员变量、方法形参或构造函数形参提供自动注入的功能。<br />
那么能不是也可以通过注解定义 Bean，从 XML 配置文件中完全移除 Bean 定义的配置呢？<br />
答案是肯定的，我们通过 Spring 5 提供的 @Component 注释就可以达到这个目标了。<br />
修改Bean的java类的代码如下，在类名前面加上 @Component注解</p>
<pre class="java">    package com.firemax.test.service;
      import java.util.ArrayList;

    import java.util.Iterator;

    import java.util.List;

    import org.apache.commons.logging.Log;

    import org.apache.commons.logging.LogFactory;

    import org.dom4j.Document;

   import org.dom4j.DocumentHelper;

   import org.dom4j.Element;

   import org.springframework.beans.factory.annotation.Autowired;

   import org.springframework.stereotype.Component;

   import com.firemax.test.hibernate.AlcorTCitys;

   import com.firemax.test.hibernate.AlcorTCitysDAO;

   import com.firemax.test.hibernate.AlcorTCountries;

   import com.firemax.test.hibernate.AlcorTCountriesDAO;

   import com.firemax.test.hibernate.AlcorTProvinces;

   import com.firemax.test.hibernate.AlcorTProvincesDAO;

   import com.firemax.test.hibernate.AlcotTDistrict;

   import com.firemax.test.hibernate.AlcotTDistrictDAO;

   @Component

   public class CountryService {

       private static Log logger = LogFactory.getLog(CountryService.class);

       @Autowired

       private AlcorTCountriesDAO  alcorTCountriesDAO;

       @Autowired

       private AlcorTProvincesDAO  alcorTProvincesDAO;

       @Autowired

       private AlcorTCitysDAO          alcorTCitysDAO;

       @Autowired

       private AlcotTDistrictDAO       alcotTDistrictDAO;

       public CountryService(){

       }

        //这里是业务逻辑的方法

        。。。。。

   }</pre>
<p>然后，我们修改配置文件applicatonContext.xml中，启用自动注入的功能，而放弃原来的&lt;bean&gt;方式的配置</p>
<p>&lt;?xml version=&#8221;0&#8243; encoding=&#8221;UTF-8&#8243;?&gt;</p>
<p>&lt;beans xmlns=&#8221;<a href="http://www.springframework.org/schema/beans&quot;">http://www.springframework.org/schema/beans&#8221;</a></p>
<p>xmlns:context=&#8221;<a href="http://www.springframework.org/schema/context&quot;">http://www.springframework.org/schema/context&#8221;</a></p>
<p>xmlns:xsi=&#8221;<a href="http://www.worg/2001/XMLSchema-instance&quot;">http://www.worg/2001/XMLSchema-instance&#8221;</a></p>
<p>xmlns:tx=&#8221;<a href="http://www.springframework.org/schema/tx&quot;">http://www.springframework.org/schema/tx&#8221;</a></p>
<p>xsi:schemaLocation=&#8221;<a href="http://www.springframework.org/schema/beans">http://www.springframework.org/schema/beans</a> <a href="http://www.springframework.org/schema/beans/spring-beans-xsd">http://www.springframework.org/schema/beans/spring-beans-xsd</a></p>
<p><a href="http://www.springframework.org/schema/context">http://www.springframework.org/schema/context</a> <a href="http://www.springframework.org/schema/context/spring-context-xsd">http://www.springframework.org/schema/context/spring-context-xsd</a></p>
<p><a href="http://www.springframework.org/schema/tx">http://www.springframework.org/schema/tx</a> <a href="http://www.springframework.org/schema/tx/spring-tx-xsd&quot;">http://www.springframework.org/schema/tx/spring-tx-xsd&#8221;</a></p>
<p>default-autowire=&#8221;autodetect&#8221;&gt;</p>
<p>&lt;bean id=&#8221;entityManagerFactory&#8221;</p>
<p>class=&#8221;org.springframework.orm.jpa.LocalEntityManagerFactoryBean&#8221;&gt;</p>
<p>&lt;property name=&#8221;persistenceUnitName&#8221; value=&#8221;testerPU&#8221; /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;bean id=&#8221;transactionManager&#8221; class=&#8221;org.springframework.orm.jpa.JpaTransactionManager&#8221;&gt;</p>
<p>&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;tx:annotation-driven transaction-manager=&#8221;transactionManager&#8221; /&gt;</p>
<p>&lt;bean id=&#8221;transactionInterceptor&#8221;</p>
<p>class=&#8221;org.springframework.transaction.interceptor.TransactionInterceptor&#8221;&gt;</p>
<p>&lt;!&#8211; 事务拦截器bean需要依赖注入一个事务管理器 &#8211;&gt;</p>
<p>&lt;property name=&#8221;transactionManager&#8221;&gt;</p>
<p>&lt;ref local=&#8221;transactionManager&#8221; /&gt;</p>
<p>&lt;/property&gt;</p>
<p>&lt;property name=&#8221;transactionAttributes&#8221;&gt;</p>
<p>&lt;!&#8211; 下面定义事务（指service里面的方法）传播属性 &#8211;&gt;</p>
<p>&lt;props&gt;</p>
<p>&lt;prop key=&#8221;insert*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;update*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;save*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;add*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;update*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;remove*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;delete*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;get*&#8221;&gt;PROPAGATION_REQUIRED,readOnly</p>
<p>&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;find*&#8221;&gt;PROPAGATION_REQUIRED,readOnly</p>
<p>&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;load*&#8221;&gt;PROPAGATION_REQUIRED,readOnly</p>
<p>&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;change*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;count*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;prop key=&#8221;*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;</p>
<p>&lt;/props&gt;</p>
<p>&lt;/property&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;!&#8211; 该 BeanPostProcessor 将自动对标注 @Autowired 的 Bean 进行注入 &#8211;&gt;</p>
<p>&lt;!&#8211;  这个Processor 已经被 &lt;context:annotation-config/&gt; 所简化<br />
&lt;bean class=&#8221;org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor&#8221;/&gt;</p>
<p>&#8211;&gt;</p>
<p>&lt;!&#8211; &lt;context:component- scan/&gt; 配置项不但启用了对类包进行扫描以实施注释驱动 Bean 定义的功能，同时还启用了注释驱动自动注入的功能（即还隐式地在内部注册了 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor），因此当使用 &lt;context:component-scan/&gt; 后，就可以将 &lt;context:annotation- config/&gt; 移除了。 &#8211;&gt;</p>
<p>&lt;context:component-scan base-package =&#8221;com.firemax&#8221;/&gt;<br />
&lt;!&#8211; 定义自动代理BeanNameAutoProxyCreator &#8211;&gt;</p>
<p>&lt;bean id=&#8221;beanNameAutoProxyCreator&#8221;</p>
<p>class=&#8221;org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator&#8221;&gt;</p>
<p>&lt;!&#8211; 指定对满足哪些bean name的bean自动生成业务代理 &#8211;&gt;</p>
<p>&lt;property name=&#8221;beanNames&#8221;&gt;</p>
<p>&lt;list&gt;</p>
<p>&lt;value&gt;*Service&lt;/value&gt;</p>
<p>&lt;/list&gt;</p>
<p>&lt;/property&gt;</p>
<p>&lt;!&#8211; 下面定义BeanNameAutoProxyCreator所需的事务拦截器  &#8211;&gt;</p>
<p>&lt;property name=&#8221;interceptorNames&#8221;&gt;</p>
<p>&lt;list&gt;</p>
<p>&lt;!&#8211; 此处可增加其他新的Interceptor &#8211;&gt;</p>
<p>&lt;value&gt;transactionInterceptor&lt;/value&gt;</p>
<p>&lt;/list&gt;</p>
<p>&lt;/property&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;!&#8211;</p>
<p>&lt;bean id=&#8221;AlcorTCountriesDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcorTCountriesDAO&#8221;&gt;</p>
<p>&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;bean id=&#8221;AlcorTProvincesDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcorTProvincesDAO&#8221;&gt;</p>
<p>&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;bean id=&#8221;AlcotTDistrictDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcotTDistrictDAO&#8221;&gt;</p>
<p>&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;bean id=&#8221;AlcorTCitysDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcorTCitysDAO&#8221;&gt;</p>
<p>&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>&lt;bean id=&#8221;CountryService&#8221; class=&#8221;com.firemax.test.service.CountryService&#8221;/&gt;</p>
<p>&#8211;&gt;</p>
<p>&lt;/beans&gt;</p>
<p>新的applicaitonContext.xml 配置文件中蓝色的部分就是原来的&lt;bean&gt;的注入方式，现在已经给屏蔽了。不需要再写。而红色部分就是使用了&lt;context:component-scan base-package =&#8221;com.firemax&#8221;/&gt; ，让spirng自动搜索，然后注入。</p>
<p>注意：</p>
<p>* 这里注入的bean 的名称是按照类的名称，把第一个字母改成小写来命名的。比如例子中的CountryService的bean的名称就是countryService.</p>
<p>* 我们也可以通过@Component(&#8220;countryService&#8221;) 这种方式来显示的定义一个bean的注入名称。但是在大多数情况下没有必要。</p>
<p>&lt;context:component-scan/&gt; 的 base-package 属性指定了需要扫描的类包，类包及其递归子包中所有的类都会被处理。</p>
<p>&lt;context:component-scan/&gt; 还允许定义过滤器将基包下的某些类纳入或排除。Spring 支持以下 4 种类型的过滤方式，通过下表说明：</p>
<p><strong>扫描过滤方式</p>
<p></strong>过滤器类型          说明</p>
<p>注释                   假如 com.firemax.test.SomeAnnotation 是一个注释类，我们可以将使用该注释的类过滤出来。</p>
<p>类名指定             通过全限定类名进行过滤，如您可以指定将 com.firemax.test.IncludeService纳入扫描，而将 com.firemax.test.NotIncludeService 排除。</p>
<p>正则表达式          通过正则表达式定义过滤的类，如下所示： com\.firemax\.test\.Default.*</p>
<p>AspectJ 表达式    通过 AspectJ 表达式定义过滤的类，如下所示： com. firemax.test..*Service+</p>
<p>下面是一个简单的例子：</p>
<pre class="java">    &lt;context:component-scan base-package="com.firemax"&gt;
          &lt;context:include-filter type="regex" 

            expression="com\.firemax\.test\.service\..*"/&gt;

        &lt;context:exclude-filter type="aspectj" 

            expression="com.firemax.test.util..*"/&gt;

    &lt;/context:component-scan&gt;</pre>
<p>默认情况下通过 @Component 定义的 Bean 都是 singleton 的，如果需要使用其它作用范围的 Bean，可以通过 @Scope 注释来达到目标，如以下代码所示：</p>
<p>通过 @Scope 指定 Bean 的作用范围</p>
<pre class="java">    package com.firemax.tester.service;
      import org.springframework.context.annotation.Scope;

    …

    @Scope("prototype")

    @Component("countryService")

    public class CountryService{

        …

    }</pre>
<p>这样，当从 Spring 容器中获取 boss Bean 时，每次返回的都是新的实例了。</p>
<p>在Spring5中引入了更多的典型化注解，@Repository ，@Service，@Controler是@Component的细化。分别表示持久层，服务层，控制层。建议使用这个注解来取代@Component</p>
<p>附上一个java Applicaiton的简单测试程序</p>
<pre class="java">    /*
       * Created on 2008-9-28

     *

     */

    package com.firemax.test.tester;

    import java.util.Iterator;

   import org.springframework.context.ApplicationContext;

   import org.springframework.context.support.FileSystemXmlApplicationContext;

   import com.firemax.test.hibernate.AlcorTCitys;

   import com.firemax.test.hibernate.AlcorTCitysDAO;

   import com.firemax.test.hibernate.AlcorTCountries;

   import com.firemax.test.hibernate.AlcorTProvinces;

   import com.firemax.test.hibernate.AlcotTDistrict;

   import com.firemax.test.hibernate.AlcotTDistrictDAO;

   import com.firemax.test.service.CountryService;

   public class Tester {

       /**

        * @param args

        */

       public static void main(String[] args) throws Exception{

           // TODO Auto-generated method stub

           ApplicationContext ctx =     new FileSystemXmlApplicationContext("/WebContent/WEB-INF/classes/applicationContext*.xml");

           String[] beans = ctx.getBeanDefinitionNames();

           for (int i = 0 ; i &lt; beans.length;i++)

           {

               System.out.println(beans[i]);

           }

           CountryService countryService= (CountryService)ctx.getBean("countryService");

           AlcorTCountries  alcorTCountries= countryService.getCountriesInfo("CN");

           System.out.println(alcorTCountries.getCountry());

           System.out.println("开始调用子类");

           System.out.println(alcorTCountries.getAlcorTProvinceses().size());

           Iterator&lt;AlcorTProvinces&gt; it = alcorTCountries.getAlcorTProvinceses().iterator();

           while (it.hasNext()){

               AlcorTProvinces  alcorTProvinces= (AlcorTProvinces)it.next();

               System.out.println(alcorTProvinces.getProvinceName());

           }

           AlcotTDistrict alcotTDistrict= new AlcotTDistrict();

           alcotTDistrict.setDistrictCode("22");

           alcotTDistrict.setDistrictName("浦东");

           AlcorTCitys alcorTCitys =countryService.getCityInfo("021");

           alcotTDistrict.setAlcorTCitys(alcorTCitys);

           countryService.saveProvinces(alcotTDistrict);

       }

   }</pre>
<p>在所有的JPOPO中，我们可以使用@Entity 这个注解来注入 JOPO。这样我们在 Persistent.xml中就不需要在 定义哪些POJO的类了。</p>
<p>感谢 JPA 感谢Spring ，终于不要频繁的去定义和修改这些Bean了</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-jpa-hibernate-five-180/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring JPA hibernate 使用方法整理（四)命名空间</title>
		<link>http://javadou.com/spring-hibernate-jpa-foure-179/</link>
		<comments>http://javadou.com/spring-hibernate-jpa-foure-179/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 09:27:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-hibernate-jpa-foure-179/</guid>
		<description><![CDATA[在（三）里面。我们引入了 <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/& gt;这个bean 来处理Autowired注解。
其实在spring 里面还有其他三个BeanPostProcessor 。总共有四个，分别是：
AutowiredAnn... ]]></description>
			<content:encoded><![CDATA[<p><a href="http://javadou.com/spring-jpa-hibernate-three-178/" target="_blank">在（三）里面</a>。我们引入了 &lt;bean class=&#8221;org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor&#8221;/&amp; gt;这个bean 来处理@Autowired注解。<br />
其实在spring 里面还有其他三个BeanPostProcessor 。总共有四个，分别是：<br />
AutowiredAnnotationBeanPostProcessor<br />
CommonAnnotationBeanPostProcessor<br />
PersistenceAnnotationBeanPostProcessor<br />
equiredAnnotationBeanPostProcessor</p>
<p>但是直接在 Spring 配置文件中定义这些 Bean 显得比较笨拙。Spring 为我们提供了一种方便的注册这些 BeanPostProcessor 的方式，这就是 &lt;context:annotation-config/&gt;</p>
<p>Spring 1 添加了一个新的 context 的 Schema 命名空间，该命名空间对注释驱动、属性文件引入、加载期织入等功能提供了便捷的配置。我们知道注释本身是不会做任何事情的，它仅提供元数据信息。要使元数据信息真正起作用，必须让负责处理这些元数据的处理器工作起来。</p>
<p>这段代码就是 启用了这个命名空间后的applicationContext.xml文件</p>
<p>&lt;?xml version=&#8221;0&#8243; encoding=&#8221;UTF-8&#8243;?&gt;<br />
&lt;beans xmlns=&#8221;http://www.springframework.org/schema/beans&#8221;<br />
xmlns:context=&#8221;http://www.springframework.org/schema/context&#8221;<br />
xmlns:xsi=&#8221;http://www.worg/2001/XMLSchema-instance&#8221;<br />
xmlns:tx=&#8221;http://www.springframework.org/schema/tx&#8221;<br />
xsi:schemaLocation=&#8221;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-xsd<br />
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-xsd<br />
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-xsd&#8221;<br />
&gt;<br />
&lt;bean id=&#8221;entityManagerFactory&#8221;<br />
class=&#8221;org.springframework.orm.jpa.LocalEntityManagerFactoryBean&#8221;&gt;<br />
&lt;property name=&#8221;persistenceUnitName&#8221; value=&#8221;testerPU&#8221; /&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id=&#8221;transactionManager&#8221; class=&#8221;org.springframework.orm.jpa.JpaTransactionManager&#8221;&gt;<br />
&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;<br />
&lt;/bean&gt;<br />
&lt;tx:annotation-driven transaction-manager=&#8221;transactionManager&#8221; /&gt;<br />
&lt;bean id=&#8221;transactionInterceptor&#8221;<br />
class=&#8221;org.springframework.transaction.interceptor.TransactionInterceptor&#8221;&gt;<br />
&lt;!&#8211; 事务拦截器bean需要依赖注入一个事务管理器 &#8211;&gt;<br />
&lt;property name=&#8221;transactionManager&#8221;&gt;<br />
&lt;ref local=&#8221;transactionManager&#8221; /&gt;<br />
&lt;/property&gt;<br />
&lt;property name=&#8221;transactionAttributes&#8221;&gt;<br />
&lt;!&#8211; 下面定义事务（指service里面的方法）传播属性 &#8211;&gt;<br />
&lt;props&gt;<br />
&lt;prop key=&#8221;insert*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;update*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;save*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;add*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;update*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;remove*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;delete*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;get*&#8221;&gt;PROPAGATION_REQUIRED,readOnly<br />
&lt;/prop&gt;<br />
&lt;prop key=&#8221;find*&#8221;&gt;PROPAGATION_REQUIRED,readOnly<br />
&lt;/prop&gt;<br />
&lt;prop key=&#8221;load*&#8221;&gt;PROPAGATION_REQUIRED,readOnly<br />
&lt;/prop&gt;<br />
&lt;prop key=&#8221;change*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;count*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;prop key=&#8221;*&#8221;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br />
&lt;/props&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;!&#8211; 该 BeanPostProcessor 将自动对标注 @Autowired 的 Bean 进行注入 &#8211;&gt;<br />
&lt;!&#8211;  这个Processor 已经被 &lt;context:annotation-config/&gt; 所简化<br />
&lt;bean class=&#8221;org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor&#8221;/&gt;<br />
&#8211;&gt;<br />
&lt;context:annotation-config/&gt;<br />
&lt;!&#8211; 定义自动代理BeanNameAutoProxyCreator &#8211;&gt;<br />
&lt;bean id=&#8221;beanNameAutoProxyCreator&#8221;<br />
class=&#8221;org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator&#8221;&gt;<br />
&lt;!&#8211; 指定对满足哪些bean name的bean自动生成业务代理 &#8211;&gt;<br />
&lt;property name=&#8221;beanNames&#8221;&gt;<br />
&lt;list&gt;<br />
&lt;value&gt;*Service&lt;/value&gt;<br />
&lt;/list&gt;<br />
&lt;/property&gt;<br />
&lt;!&#8211; 下面定义BeanNameAutoProxyCreator所需的事务拦截器  &#8211;&gt;<br />
&lt;property name=&#8221;interceptorNames&#8221;&gt;<br />
&lt;list&gt;<br />
&lt;!&#8211; 此处可增加其他新的Interceptor &#8211;&gt;<br />
&lt;value&gt;transactionInterceptor&lt;/value&gt;<br />
&lt;/list&gt;<br />
&lt;/property&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id=&#8221;AlcorTCountriesDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcorTCountriesDAO&#8221;&gt;<br />
&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id=&#8221;AlcorTProvincesDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcorTProvincesDAO&#8221;&gt;<br />
&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id=&#8221;AlcotTDistrictDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcotTDistrictDAO&#8221;&gt;<br />
&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id=&#8221;AlcorTCitysDAO&#8221; class=&#8221;com.firemax.test.hibernate.AlcorTCitysDAO&#8221;&gt;<br />
&lt;property name=&#8221;entityManagerFactory&#8221; ref=&#8221;entityManagerFactory&#8221; /&gt;<br />
&lt;/bean&gt;<br />
&lt;bean id=&#8221;CountryService&#8221; class=&#8221;com.firemax.test.service.CountryService&#8221;/&gt;<br />
&lt;/beans&gt;</p>
<p>注意2段标红的内容，就是这次更新的配置内容。在配置文件中使用 context 命名空间之前，必须在 &lt;beans&gt; 元素中声明 context 命名空间。</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-hibernate-jpa-foure-179/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring hibernate使用方法整理@Autowired(三)</title>
		<link>http://javadou.com/spring-jpa-hibernate-three-178/</link>
		<comments>http://javadou.com/spring-jpa-hibernate-three-178/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 08:25:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-jpa-hibernate-three-178/</guid>
		<description><![CDATA[是在我们编写spring 框架的代码时候。一直遵循是这样一个规则：所有在spring中注入的bean 都建议定义成私有的域变量。并且要配套写上 get 和 set方法。虽然可以通过eclipse等工具来自动生成。但是还是会引起程序阅读... ]]></description>
			<content:encoded><![CDATA[<p>通过 前两篇文章的介绍。我们已经做了初步的简化程序。<br />
但是在我们编写spring 框架的代码时候。一直遵循是这样一个规则：所有在spring中注入的bean 都建议定义成私有的域变量。并且要配套写上 get 和 set方法。虽然可以通过eclipse等工具来自动生成。但是还是会引起程序阅读性上的不便。那么既然注解这么强大。是否可以也把他精简掉呢？</p>
<p>当然可以。这个标签就是@Autowired</p>
<p>Spring 5 引入了 @Autowired 注释，它可以对类成员变量、方法及构造函数进行标注，完成自动装配的工作。</p>
<p>要实现我们要精简程序的目的。需要这样来处理：</p>
<p>* 在applicationContext.xml中加入：</p>
<p>&lt;!&#8211; 该 BeanPostProcessor 将自动对标注 @Autowired 的 Bean 进行注入 &#8211;&gt;<br />
&lt;bean class=&#8221;org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor&#8221;/&gt;</p>
<p>* 修改在原来注入spirng容器中的bean的方法。在域变量上加上标签@Autowired,并且去掉 相应的get 和set方法<br />
/*国家，省份，城市，城区信息维护服务<br />
* Created on 2008-9-26<br />
*<br />
* 徐泽宇 roamer<br />
*/<br />
package com.firemax.test.service;<br />
import java.util.ArrayList;<br />
import java.util.Iterator;<br />
import java.util.List;<br />
import org.apache.commons.logging.Log;<br />
import org.apache.commons.logging.LogFactory;<br />
import org.dom4j.Document;<br />
import org.dom4j.DocumentHelper;<br />
import org.dom4j.Element;<br />
import org.springframework.beans.factory.annotation.Autowired;<br />
import com.firemax.test.hibernate.AlcorTCitys;<br />
import com.firemax.test.hibernate.AlcorTCitysDAO;<br />
import com.firemax.test.hibernate.AlcorTCountries;<br />
import com.firemax.test.hibernate.AlcorTCountriesDAO;<br />
import com.firemax.test.hibernate.AlcorTProvinces;<br />
import com.firemax.test.hibernate.AlcorTProvincesDAO;<br />
import com.firemax.test.hibernate.AlcotTDistrict;<br />
import com.firemax.test.hibernate.AlcotTDistrictDAO;<br />
public class CountryService {<br />
private static Log logger = LogFactory.getLog(CountryService.class);<br />
@Autowired<br />
private AlcorTCountriesDAO  alcorTCountriesDAO;<br />
@Autowired<br />
private AlcorTProvincesDAO  alcorTProvincesDAO;<br />
@Autowired<br />
private AlcorTCitysDAO          alcorTCitysDAO;<br />
@Autowired<br />
private AlcotTDistrictDAO       alcotTDistrictDAO;<br />
public CountryService(){<br />
}<br />
/**修改一个国家信息<br />
* @param alcorTCountries<br />
* @throws Exception<br />
*/<br />
public void updateCountry(AlcorTCountries alcorTCountries ) throws Exception{<br />
this.alcorTCountriesDAO.update(alcorTCountries);<br />
}<br />
&#8230;.<br />
//这里去掉了哪些DAO 变量的get 和set 方法。<br />
}</p>
<p>* 在applicatonContext.xml中 把原来 引用的&lt;porpery &gt;标签也去掉。<br />
&lt;bean id=&#8221;CountryService&#8221; class=&#8221;com.firemax.test.service.CountryService&#8221;&gt;<br />
&lt;property name=&#8221;alcorTCountriesDAO&#8221; ref=&#8221;AlcorTCountriesDAO&#8221; /&gt;<br />
&lt;property name=&#8221;alcorTProvincesDAO&#8221; ref=&#8221;AlcorTProvincesDAO&#8221; /&gt;<br />
&lt;property name=&#8221;alcorTCitysDAO&#8221; ref=&#8221;AlcorTCitysDAO&#8221; /&gt;<br />
&lt;property name=&#8221;alcotTDistrictDAO&#8221; ref=&#8221;AlcotTDistrictDAO&#8221; /&gt;<br />
&lt;/bean&gt;<br />
修改成<br />
&lt;bean id=&#8221;CountryService&#8221; class=&#8221;com.firemax.test.service.CountryService&#8221;&gt;<br />
&lt;/bean&gt;<br />
当然，我们也可以在构造函数上使用@Auwowired 注解 。如果构造函数有两个入参，分别是 bean1 和 bean2，@Autowired 将分别寻找和它们类型匹配的 Bean，将它们作为 CountryService (Bean1 bean1 ,Bean2 bean2) 的入参来创建 CountryService  Bean。</p>
<p>在运行一下你的业务程序。如果没有错误。恭喜你。这个步骤我们又完成了。</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-jpa-hibernate-three-178/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring 2.5 JPA hibernate 使用方法的整理（二）</title>
		<link>http://javadou.com/spring-jpa-hibernate-two-177/</link>
		<comments>http://javadou.com/spring-jpa-hibernate-two-177/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 07:22:00 +0000</pubDate>
		<dc:creator>阿超</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://javadou.com/spring-jpa-hibernate-two-177/</guid>
		<description><![CDATA[通过上面一步骤。我们简化了hibernate中扰人的 xxxxx.hbm.xml文件。那么是否可以再进行简化呢？
那么，我们在这一步骤的目的，就是把整个 hibernate.cfg.xml都给简化了。 

依然是利用注解注入的方式。通过jpa 我们可以把 ... ]]></description>
			<content:encoded><![CDATA[<p>&#160;&#160; <a href="http://javadou.com/spring-jpa-hibernate-one-176/" target="_blank">通过上面一步骤</a>。我们简化了hibernate中扰人的 xxxxx.hbm.xml文件。那么是否可以再进行简化呢？    <br />那么，我们在这一步骤的目的，就是把整个 hibernate.cfg.xml都给简化了。 </p>
<p>依然是利用注解注入的方式。通过jpa 我们可以把 hibernate.cfg.xml中那些 mapping classes再次简化与无形。 </p>
<p>&#160;&#160;&#160; 在applicationContext.xml中进行如下配置   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;?xml version=&quot;0&quot; encoding=&quot;UTF-8&quot;?&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; xmlns:xsi=&quot;http://www.worg/2001/XMLSchema-instance&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-xsd&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; xmlns:tx=&quot;http://www.springframework.org/schema/tx&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;entityManagerFactory&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; class=&quot;org.springframework.orm.jpa.LocalEntityManagerFactoryBean&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;persistenceUnitName&quot; value=&quot;testerPU&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;transactionManager&quot; class=&quot;org.springframework.orm.jpa.JpaTransactionManager&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;entityManagerFactory&quot; ref=&quot;entityManagerFactory&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;tx:annotation-driven transaction-manager=&quot;transactionManager&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;transactionInterceptor&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; class=&quot;org.springframework.transaction.interceptor.TransactionInterceptor&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 事务拦截器bean需要依赖注入一个事务管理器 &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;transactionManager&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;ref local=&quot;transactionManager&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;transactionAttributes&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 下面定义事务（指service里面的方法）传播属性 &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;props&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;insert*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;update*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;save*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;add*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;update*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;remove*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;delete*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;get*&quot;&gt;PROPAGATION_REQUIRED,readOnly    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;find*&quot;&gt;PROPAGATION_REQUIRED,readOnly    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;load*&quot;&gt;PROPAGATION_REQUIRED,readOnly    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;change*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;count*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;prop key=&quot;*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/props&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 定义自动代理BeanNameAutoProxyCreator &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;beanNameAutoProxyCreator&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; class=&quot;org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 指定对满足哪些bean name的bean自动生成业务代理 &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;beanNames&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;list&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;value&gt;*Service&lt;/value&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/list&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 下面定义BeanNameAutoProxyCreator所需的事务拦截器&#160; &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;interceptorNames&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;list&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;!&#8211; 此处可增加其他新的Interceptor &#8211;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;value&gt;transactionInterceptor&lt;/value&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/list&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/property&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;AlcorTCountriesDAO&quot; class=&quot;com.firemax.test.hibernate.AlcorTCountriesDAO&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;entityManagerFactory&quot; ref=&quot;entityManagerFactory&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;AlcorTProvincesDAO&quot; class=&quot;com.firemax.test.hibernate.AlcorTProvincesDAO&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;entityManagerFactory&quot; ref=&quot;entityManagerFactory&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;AlcotTDistrictDAO&quot; class=&quot;com.firemax.test.hibernate.AlcotTDistrictDAO&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;entityManagerFactory&quot; ref=&quot;entityManagerFactory&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;AlcorTCitysDAO&quot; class=&quot;com.firemax.test.hibernate.AlcorTCitysDAO&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;entityManagerFactory&quot; ref=&quot;entityManagerFactory&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;bean id=&quot;CountryService&quot; class=&quot;com.firemax.test.service.CountryService&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;alcorTCountriesDAO&quot; ref=&quot;AlcorTCountriesDAO&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;alcorTProvincesDAO&quot; ref=&quot;AlcorTProvincesDAO&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;alcorTCitysDAO&quot; ref=&quot;AlcorTCitysDAO&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;alcotTDistrictDAO&quot; ref=&quot;AlcotTDistrictDAO&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/bean&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/beans&gt; </p>
<p>&#160;&#160;&#160;&#160;&#160; 注意红色部分。这部分和（一）里面提到的那个applicationContext.xml中使用的bean是不同的。这里面已经用到了spring 的jpa部分。   <br />&#160;&#160;&#160;&#160;&#160; 其中 &lt;property name=&quot;persistenceUnitName&quot; value=&quot;testerPU&quot; /&gt;&#160; 是指向了一个 jpa的PU（Persistent Units） </p>
<p>&#160;&#160;&#160;&#160;&#160; 那么这个 是在哪里定义的呢？   <br />&#160;&#160;&#160;&#160;&#160; 这里的定义是在你的 classes（src）目录下META-INF下的persistence.xml文件中来定义    <br />&#160;&#160;&#160;&#160;&#160; persistence.xml文件内容如下： </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;?xml version=&quot;0&quot; encoding=&quot;UTF-8&quot;?&gt;   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;persistence xmlns=&quot;http://java.sun.com/xml/ns/persistence&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; xmlns:xsi=&quot;http://www.worg/2001/XMLSchema-instance&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/persistence    <br />http://java.sun.com/xml/ns/persistence/persistence_1_xsd&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; version=&quot;0&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;persistence-unit name=&quot;testerPU&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; transaction-type=&quot;RESOURCE_LOCAL&quot;&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;provider&gt;org.hibernate.ejb.HibernatePersistence&lt;/provider&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;class&gt;com.firemax.test.hibernate.AlcorTCountries&lt;/class&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;class&gt;com.firemax.test.hibernate.AlcorTProvinces&lt;/class&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;class&gt;com.firemax.test.hibernate.AlcotTDistrict&lt;/class&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;class&gt;com.firemax.test.hibernate.AlcorTCitys&lt;/class&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;properties&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.connection.driver_class&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; value=&quot;com.mysql.jdbc.Driver&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.connection.url&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; value=&quot;jdbc:mysql://localhost:3306/alcorweb?useUnicode=true&amp;characterEncoding=utf-8&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.connection.username&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; value=&quot;alcorweb&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.connection.password&quot;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; value=&quot;alcorweb&quot; /&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.connection.provider_class&quot; value=&quot;org.hibernate.connection.C3P0ConnectionProvider&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.c3pmax_size&quot; value=&quot;100&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.c3pmin_size&quot;&#160; value=&quot;20&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.c3ptimeout&quot;&#160;&#160; value=&quot;120&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.c3pmax_statements&quot; value=&quot;0&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.c3pidle_test_period&quot;&#160; value=&quot;120&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.c3pacquire_increment&quot; value=&quot;5&#160; &quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.cache.provider_class&quot; value=&quot;org.hibernate.cache.EhCacheProvider&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.cache.use_query_cache&quot; value=&quot;false&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.show_sql&quot; value=&quot;false&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.useUnicode&quot; value=&quot;true&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;property name=&quot;hibernate.characterEncoding&quot; value=&quot;utf8&quot;/&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/properties&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/persistence-unit&gt;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/persistence&gt; </p>
<p>&#160;&#160;&#160;&#160;&#160; 仔细观察他的代码，我们发现其实和hibernate.cfg.xml和相似。都有指向pojo的定义 和 database连接的定义。先别着急。我们这次的优化，就先完成这个目标。主要是引入的spring的jpa框架。   <br />&#160;&#160;&#160;&#160;&#160; 后面将介绍更进一步的优化。来展示jpa 和 注释注入的能力。</p>
]]></content:encoded>
			<wfw:commentRss>http://javadou.com/spring-jpa-hibernate-two-177/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
