??xml version="1.0" encoding="utf-8" standalone="yes"?> ------------------------------------------- ------------------------------------------ For all those out there using Spring together with Struts, i created
a small howTo regarding automatic generation of relevant files,
especially the boring action-servlet-xml file which must be in synch
with your struts-config.xml, at least for all Struts actions which
should be injected by Spring. Lets start with the Action class: ClientManager clientManagerService; /** With this tags, the ant build target outlined below will create a
struts-config.xml and the necessary action-servlet.xml needed by
Spring. Lets see how the target looks: <fileset dir="c:/xdoclet-1.2.2" includes="*.jar"/> <taskdef name="springdoclet" <target name="myTest"> <springdoclet destDir="c:\" verbose="true"> Be sure to modify the classpath definition and the destDir values of
springdoclet and webdoclet to suit your needs. Right now the Spring
task only searches for Actions in order to create action-servlet.xml,
if you also want to create your normal service beans like
ClientManagerService, you should create another springdoclet task and
output things to applicationContext.xml if you like. But this is mostly users choice, as you know, Spring supports from
one to many bean definition files and its up to you how you want to
have your spring xml world. This will be created when you run the mentioned target: (action-servlet.xml) <beans <bean <property name="clientManagerService"> <ref bean="clientManagerService"/> </bean> <!-- <!DOCTYPE struts-config PUBLIC "-//Apache Software
Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"> <struts-config> <!-- ========== Data Sources Definitions =================================== --> <!-- ========== Form Bean Definitions =================================== --> <!-- <!-- ========== Global Exceptions Definitions =================================== --> <!-- ========== Global Forward Definitions =================================== --> <!-- ========== Action Mapping Definitions =================================== --> <!-- If you have non XDoclet actions, define them in a file
called struts-actions.xml and place it in your merge directory. --> <!-- Define your Struts controller in a file called struts-controller.xml and place it in your merge directory. --> <!-- Define your Struts message-resources in a file called
struts-message-resources.xml and place it in your merge directory.
--> <!-- Define your Struts plugins in a file called struts-plugins.xml and place it in your merge directory. -->
XDoclet的build.xml写法
Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=
---------------------------------------------
/**
* Action to delete a Client
* Date: 09.02.2005
* Time: 15:29:15
*
* @author Logemann - Logentis e.K. (ml@logentis.de)
* @version $Id$
* @struts.action path="clientDelete" validate="false"
* type="org.springframework.web.struts.DelegatingActionProxy"
* name="emptyform"
* @struts.action-forward name="back"
* path="/clientManager.html" redirect="true"
* @spring.bean name="clientDelete"
*/
public class ClientDeleteAction extends Action {
* Spring injection
*
* @param clientManagerService clientManagerService
* @spring.property ref="clientManagerService"
*/
public void setClientManagerService(ClientManager clientManagerService) {
this.clientManagerService = clientManagerService;
}
[..]
<path id="classpath">
<fileset dir="c:/j2sdkee1.3.1/lib" includes="*.jar"/>
<fileset dir="c:/struts/lib" includes="struts.jar"/>
</path>
classname="xdoclet.modules.spring.SpringDocletTask"
classpathref="classpath"/>
<taskdef name="webdoclet"
classname="xdoclet.modules.web.WebDocletTask"
classpathref="classpath"/>
<webdoclet destDir="c:\" force="true" verbose="true">
<fileset dir="${src.dir}">
<include name="**/*Form.java" />
<include name="**/*Action.java" />
<include name="**/*Servlet.java" />
</fileset>
<strutsconfigxml version="1.1" validateXml="true"/>
</webdoclet>
<fileset dir="${src.dir}">
<include name="**/*Action.java" />
</fileset>
<springxml destinationFile="action-servlet.xml"/>
</springdoclet>
</target>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
default-autowire="no"
default-lazy-init="false"
default-dependency-check="none"
>
name="clientDelete"
class="de.logentis.versysng.action.clientmanager.ClientDeleteAction"
>
</property>
To include additional bean definitions for Spring in the generated
application context file, add a file to your XDoclet merge directory
called spring-beans.xml that contains the <bean></bean> markup.
-->
</beans>
(struts-config.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Define your Struts data sources in a file called struts-data-sources.xml and place
it in your merge directory.
-->
<form-beans>
If you have non XDoclet forms, define them in a file called struts-forms.xml and
place it in your merge directory.
-->
</form-beans>
<!--
Define your exceptions in a file called global-exceptions.xml and place
it in your merge directory.
-->
<!--
Define your forwards in a file called global-forwards.xml and place
it in your merge directory.
-->
<action-mappings>
<action
path="clientDelete"
type="org.springframework.web.struts.DelegatingActionProxy"
name="emptyform"
scope="request"
unknown="false"
validate="false"
>
<forward
name="back"
path="/clientManager.html"
redirect="true"
/>
</action>
</action-mappings>
CHAPTER 2 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
CHAPTER 3 The Sample Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
PART 2 ???Spring Basics
CHAPTER 4 Introducing Inversion of Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
CHAPTER 5 Beyond the Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
PART 3 ???Aspect Oriented Programming
with Spring
CHAPTER 6 Introducing Spring AOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
CHAPTER 7 More on Spring AOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
PART 4 ???Data Access with Spring
CHAPTER 8 Spring JDBC Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
CHAPTER 9 Using Hibernate in Spring Applications . . . . . . . . . . . . . . . . . . . . . . . 279
CHAPTER 10 iBATIS Integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
vi ■CONTENTS AT A GLANCE
PART 5 ???Spring in the Middle Tier
CHAPTER 11 Designing and Implementing Spring-Based Applications . . . . . . 353
CHAPTER 12 Transaction Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
CHAPTER 13 Spring and J2EE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
CHAPTER 14 Job Scheduling with Spring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 487
CHAPTER 15 Mail Support in Spring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517
CHAPTER 16 Using Spring Remoting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 549
PART 6 ???Web Applications with Spring
CHAPTER 17 Web Applications with Spring MVC . . . . . . . . . . . . . . . . . . . . . . . . . . 599
CHAPTER 18 Beyond JSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645
CHAPTER 19 Spring and Struts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 679
PART 7 ???Appendixes
APPENDIX A Testing with Spring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 697
APPENDIX B The Spring Rich Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711
APPENDIX C Spring IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 729
APPENDIX D The Future of Spring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 743
<bean id="transactionManager" //?/SPAN>JDBC Transaction的封?/SPAN>
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<bean id="transactionManager" //?/SPAN>Hibernate事务的封?/SPAN>
class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="transactionManager"http://?/SPAN>JDO事务的封?/SPAN>
class="org.springframework.orm.jdo.JdoTransactionManager">
<property name="persistenceManagerFactory">
<ref bean="persistenceManagerFactory"/>
</property>
</bean>
<bean id="transactionManager" //?/SPAN>JTA 事务的封?/SPAN>
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName">
<value>java:/TransactionManager</value>
</property>
</bean>
<bean id="courseService"http://利用AOPQ将TransactionManager和普通的Service~织hQ实C务?/SPAN>
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyInterfaces">//~织后对外的接口
<list>
<value>com.springinaction.training.service.CourseService</value>
</list>
</property>
<property name="target">//目标
<ref bean="courseServiceTarget"/>
</property>
<property name="transactionManager">//植入的事务管理?/SPAN>
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributeSource">//事务的参敎ͼ隔离度,Ҏ(gu)名等Q?/SPAN>
<ref bean="attributeSource"/>
</property>
</bean>
有两U手D:(x)1、?/SPAN>HibernateTemplateQ?/SPAN>2、?/SPAN>HibernateDaoSupportQ实际上Q?/SPAN>HibernateDaoSupport本n是?/SPAN>HibernateTemplate的一个封装)(j)
一切尽在代码中Q查?/SPAN>API唉!
注意Qhibernate 2.X和hibernate3.X的区别,我用的是2.X ?nbsp;
package com.company.example.dao;
import java.util.List;
import com.company.example.model.Student;
public interface StudentDao {
public abstract Student getStudent(final Integer id);
public abstract void updateStudent(Student student);
public abstract List findStudentsByLastName(String lastName);
}
==================
package com.company.example.dao.hibernateImpl;
import java.util.List;
import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import org.springframework.orm.hibernate.HibernateCallback;
import org.springframework.orm.hibernate.HibernateTemplate;
import com.company.example.dao.StudentDao;
import com.company.example.model.Student;
public class StudentDaoHibernate implements StudentDao {
HibernateTemplate hibernateTemplate;
public static void main(String[] args) {
}
public HibernateTemplate getHibernateTemplate() {
return hibernateTemplate;
}
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
public Student getStudent(final Integer id) {
return (Student) hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException {
return session.load(Student.class, id);
}
});
}
public Student getStudent2(Integer id) {
return (Student) hibernateTemplate.load(Student.class, id);
}
public void updateStudent(Student student) {
hibernateTemplate.update(student);
}
public List findStudentsByLastName(String lastName) {
return hibernateTemplate.find("from Student student "
+ "where student.lastName = ?", lastName, Hibernate.STRING);
}
}
public class StudentDaoHibernate extends HibernateDaoSupport
implements StudentDao {
...........
}
======The Spring XML Configuration===========
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"<beans>
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/trainingDatasource</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
<property name="mappingResources">
<list> <!--list of each hbm.xml-->
<value>Student.hbm.xml</value>
<value>Course.hbm.xml</value>
</list>
</property>
<property name="mappingDirectoryLocations">
<list>
<!--list the directory of the hbm.xml, including each xml file in the dir-->
<value>classpath:/com/springinaction/training/model</value>
</list>
</property>
</bean>
<bean id="hibernateTemplate"
class="org.springframework.orm.hibernate.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="studentDao" class="com.company.example.dao.hibernateImpl.StudentDaoHibernate">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate"/>
</property>
</bean>
<bean id="courseDao" class="com.company.example.dao.hibernateImpl.CourseDaoHibernate">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate"/>
</property>
</bean>
</beans>
装所有的数据库访问实玎ͼ包括JDBC,JDO,Hibernate{?/SPAN>
Spring的异怸般都?/SPAN>RuntimeExceptionQ数据访问的根异常是DataAccessExceptionQ所有的Spring的数据访问异帔Rl承DataAccessException。此?/SPAN>DataAccessException?/SPAN>nestedRuntimeException子类中,已经所有的异常栈都q行了记录?/SPAN>
Spring?/SPAN>DAO异常Ҏ(gu)有底层的DAO讉K实现层的异常q行了统一的封装,q给Z更ؓ(f)有意义的异常?/SPAN>
CleanupFailureDataAccessExceptionQ清除失败异?/SPAN>
DataAccessResourceFailureExceptionQ资源访问异?/SPAN>
DataIntegrityViolationExceptionQ完整性约束异?/SPAN>
DataRetrievalFailureExceptionQ数据获取异?/SPAN>
DeadlockLoserDataAccessExceptionQ死锁访问异?/SPAN>
IncorrectUpdateSemanticsDataAccessExceptionQ更新出错异?/SPAN>
InvalidDataAccessApiUsageExceptionQ无效数据访?/SPAN>API使用异常
InvalidDataAccessResourceUsageExceptionQ无效数据访问资源用异?/SPAN>
OptimisticLockingFailureExceptionQ乐观锁p|异常
TypeMismatchDataAccessExceptionQ类型匹配失败异?/SPAN>
UncategorizedDataAccessExceptionQ其他原因异?BR>
Spring使用Template?/SPAN>Callback模式完成了对底层实现的统一装Q其?/SPAN>Template负责完成那些通用的功能(处理事务、管理资源、处理异常)(j)Q?/SPAN>Callback则完成变化的那部分内容(创徏statement、设定参?/SPAN>parameter、生成数据集resultQ。参考图4.2?/SPAN>4.3太重要了?/SPAN>
正如前面已经提到的,Introduction和前面的四个advice是有很大的区别的Q?/SPAN>introduction用于l?/SPAN>target引入新的接口Q例如锁Q状态等功能Q,生成一?/SPAN>mix-in的接口。而普通的advice只是在原有接口基上增加附加内宏V?/SPAN>
?/SPAN>Spring中,完成一?/SPAN>introduction需要三个内容:(x)1、将要添加的新接口的定义Q?/SPAN>2、该新接口的实现Q在实现?/SPAN>class中,必须实现Spring?/SPAN>IntroductionInterceptor接口Q?/SPAN>Spring in action原文有误Q,3?/SPAN>IntroductionAdvisor接口的实?/SPAN>?/SPAN>
public interface IntroductionInterceptor extends MethodInterceptor {
boolean implementsInterface(Class intf);
java.lang.Object invoke(MethodInvocation invocation) //此方法来源于MethodInterceptor
}
其中implementsInterfaceҎ(gu)q回一?/SPAN>boolean|此方法用于判断该introduction实现是否实现了某个接口―?/SPAN>intf参数。所有对intf接口的调用都?x){发给invokeҎ(gu)Q由invokeҎ(gu)完成相应的Q务。下面给Z子(l某个类d是否auditable功能Q:(x)
public interface Auditable {//1?/SPAN>auditable接口的定?/SPAN>
void setLastModifiedDate(Date date);
Date getLastModifiedDate();
}
public class AuditableMixin
implements IntroductionInterceptor, Auditable {//2?/SPAN>auditable接口的实玎ͼ同时要实?/SPAN>IntroductionInterceptor接口
public boolean implementsInterface(Class intf) {
return intf.isAssignableFrom(Auditable.class); // AuditableMixin实现?/SPAN>Auditablecȝ功能
}
public Object invoke(MethodInvocation m) throws Throwable {
if (implementsInterface(m.getMethod().getDeclaringClass())) {
//?/SPAN>invoke的参?/SPAN>mq行判断Q当前的调用是否?/SPAN>implementsInterface范围内,卻I当前的调用是否是auditable接口中的Ҏ(gu)Q?/SPAN>
return m.getMethod().invoke(this, m.getArguments());
//q里?/SPAN>this是自己Q调用引入的Ҏ(gu)Q属?/SPAN>auditable接口的方法)(j)Q这样也qtargetd了新?/SPAN>auditable接口?/SPAN>
} else {
return m.proceed();//其他Ҏ(gu)的调用?/SPAN>
}
}
private Date lastModifiedDate; //实现auditable接口?/SPAN>
public Date getLastModifiedDate() {
return lastModifiedDate;
}
public void setLastModifiedDate(Date lastModifiedDate) {
this.lastModifiedDate = lastModifiedDate;
}
}
?/SPAN>Spring中,除了上面直接实现IntroductionInterceptor接口之外Q还可以通过l承DelegatingIntroductionInterceptorcd现。其?/SPAN>DelegatingIntroductionInterceptorl出?/SPAN>IntroductionInterceptor接口中的两个Ҏ(gu)Q?/SPAN>implementsInterfaceQ?/SPAN>invokeQ的默认实现Q你仅需要实?/SPAN>auditable接口卛_?/SPAN>
通过跟踪Spring源代码可以发玎ͼ(x)DelegatingIntroductionInterceptor?/SPAN>implementsInterface Q在IntroductionInfoSupportcMQ和invokeҎ(gu)与上面的代码的Ş式基本一致。下面是利用DelegatingIntroductionInterceptor写出?/SPAN>AuditableMixinQ?/SPAN>
public class AuditableMixin
extends DelegatingIntroductionInterceptor implements Auditable {
private Date lastModifiedDate;
public Date getLastModifiedDate() {
return lastModifiedDate;
}
public void setLastModifiedDate(Date lastModifiedDate) {
this.lastModifiedDate = lastModifiedDate;
}
}
注意C点:(x)上面的两?/SPAN>AuditableMixin的实现都仅仅是给Targetd行ؓ(f)Q但是未曾改?/SPAN>Target的原有行为(因ؓ(f)?/SPAN>invokeҎ(gu)的实CQ还是会(x)转发l?/SPAN>TargetQ。如果需要改?/SPAN>Target的行?SPAN style="COLOR: red">Q例如给Target增加lock接口Q一旦处?/SPAN>locked状态,那么再调?/SPAN>Target的方法就?x)出现异常?j)Q这需要自己写代码修改invokeҎ(gu)?/SPAN>
public class ImmutableMixin
extends DelegatingIntroductionInterceptor implements Immutable {
private boolean immutable;
public void setImmutable(boolean immutable) {
this.immutable = immutable;
}
public Object invoke(MethodInvocation mi) throws Throwable {
String name = mi.getMethod().getName();
if (immutable && name.indexOf("set") == 0) { //q里一旦已l是immutable了,那么׃可以调用setXXXҎ(gu)了,q也改变了Target的行为,而不是前面的仅增加接口?/SPAN>
throw new IllegalModificationException();
}
return super.invoke(mi);
}
}
Spring中的Introduction需要有自己?/SPAN>advisor: IntroductionAdvisor
PointCuts用于定义所需要“拦截”的class?qing)?/SPAN>method。分为静态、动态两U?/SPAN>pointcut。其中静?/SPAN>pointcuts仅和class name, method name相关Q可以在配置文g中通过正则表达式进行部|Ԍ因此它们都可以在q行前进行确认。而动?/SPAN>pointcuts则需要考虑到方法的参数Q在q行时动态的认pointcuts。一般来_(d)都是Ҏ(gu)method?/SPAN>class的名字来q行。其涉及(qing)到的接口如下定义Q?/SPAN>
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
public interface ClassFilter {
boolean matches(Class clazz);
}
public interface MethodMatcher {
boolean matches(Method m, Class targetClass);
boolean isRuntime();
boolean matches(Method m, Class targetClass, Object[] args);
}
两种静?/SPAN>pointcut的实玎ͼ(x)
NameMatchMethodPointcutQ只能对Ҏ(gu)名进行判别?/SPAN>
RegexpMethodPointcutQ可以对cd、方法名使用正则表达式判别?/SPAN>
<beans>
<bean id="maidServiceTarget"
class="com.springinaction.chapter03.cleaning.MaidService"/>
<bean id="queryInterceptor" class="com.springinaction.chapter03.cleaning.QueryInterceptor"/>
<bean id="queryPointcutAdvisor"
class="org.springframework.aop.support.RegExpPointcutAdvisor">
<property name="pattern">
<value>.*get.+By.+</value>
</property>
<property name="advice">
<ref bean="queryInterceptor"/>
</property>
</bean>
<bean id="maidService"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>com.springinaction.chapter03.cleaning.MaidService</value>
</property>
<property name="interceptorNames">
<list>
<value>queryPointcutAdvisor</value>
</list>
</property>
<property name="target">
<value ref="maidServiceTarget">
</property>
</bean>
</beans>
一U动?/SPAN>pointcut的实玎ͼ(x)
ControlFlowPointcutQ根据当前运行栈的情况,军_当前?/SPAN>advice是否需要被触发。因为它完全Zq行时栈的情况做决策Q所以运行速度肯定?x)变慢?/SPAN>
<beans>
<bean id="myServiceTarget" class="MyServiceImpl"/>
<bean id="servletInterceptor" class="MyServletInterceptor"/>
<bean id="servletPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
<constructor-arg>
<value>javax.servlet.http.HttpServlet</value>
</constructor-arg>
</bean>
<bean id="servletAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice">
<ref bean="servletInterceptor"/>
</property>
<property name="pointcut">
<ref bean="servletPointcut"/>
</property>
</bean>
<bean id="service" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>MyService</value>
</property>
<property name="interceptorNames">
<list>
<value>servletAdvisor</value>
</list>
</property>
<property name="target">
<value ref="myServiceTarget">
</property>
</bean>
</beans>
前面已经提到Q?/SPAN>advisor是是PointCut?/SPAN>Advice的综合体Q完整描qC一?/SPAN>advice会(x)?/SPAN>pointcut所定义的位|被触发。也是_(d)它包含了pointcut?/SPAN>advice两项内容Q这两项内容则用于分别给?/SPAN>advice调用所发生的位|和发生的内宏V其接口如下Q?/SPAN>
public interface PointcutAdvisor {
Pointcut getPointcut();
Advice getAdvice();
}1?SPAN style="FONT: 7pt 'Times New Roman'"> around adviceQ所?/SPAN>around advice必须实现MethodInterceptor接口Q注?/SPAN>invokeҎ(gu)的参?/SPAN>invocation?/SPAN>MethodInvocation接口Q在此中包含了许多信息,包括其所装的方法及(qing)其参敎ͼAOP proxy?/SPAN>Jointcut{?/SPAN>
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
在实?/SPAN>around adviceӞ?/SPAN>before advice?/SPAN>after advice有着两个很大的区别:(x)1、必dinvokeҎ(gu)中调?/SPAN>MethodInvocation.proceed()Q这h能将所有调用gl下去,调用target对象?/SPAN>methodQ?/SPAN>2、必自p回一?/SPAN>objectQ该object甚至可以?/SPAN>target’s method的返回g一栗?/SPAN>
2?SPAN style="FONT: 7pt 'Times New Roman'"> before adviceQ在jointcut执行之前Q运?/SPAN>advice。必d?/SPAN>MethodBeforeAdvice接口?/SPAN>
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method m, Object[] args, Object target) throws Throwable;
}
3?SPAN style="FONT: 7pt 'Times New Roman'"> after adviceQ在jointcut执行之后Q运?/SPAN>advice。必d?/SPAN>AfterReturningAdvice接口?/SPAN>
public interface AfterReturningAdvice extends Advice {
void afterReturning(Object returnValue, Method m, Object[] args, Object target)
throws Throwable;
}
4?SPAN style="FONT: 7pt 'Times New Roman'"> throws adviceQ在jointcut执行出现异常的时候,q行?/SPAN>advice。必d?/SPAN>ThrowsAdvice接口。但是此接口只是一个标识接口,必须实现此外实现下面的方法:(x)
afterThrowing([Method], [args], [target], subclassOfThrowable)
q接点(JoinPointQ:(x)E序q行q程中的某个阶段炏V如某个Ҏ(gu)调用Q或者某个异常被抛出?/SPAN>
处理逻辑Q?/SPAN>AdviceQ:(x)在某个连接点所采用的处理逻辑。处理逻辑的调用模式通常有三U:(x)
i. AroundQ在q接点前后插入预处理q程和后处理q程?/SPAN>
ii. BeforeQ仅在连接点之前插入预处理过E?/SPAN>
iii. AfterQ在q接点之后进行处理?/SPAN>
iv. ThrowQ在q接Ҏ(gu)出异常时q行异常处理?/SPAN>
切点Q?/SPAN>PointCutQ:(x)一pdq接点的集合Q它指明处理方式Q?/SPAN>AdviceQ将在何处被触发Q可以用正则表辑ּ表达?/SPAN>
AdvisorQ是PointCut?/SPAN>Advice的综合体Q完整描qC一?/SPAN>advice会(x)?/SPAN>pointcut所定义的位|被触发?/SPAN>
IntroductionQؓ(f)advised object加上一定的Ҏ(gu)或者数据成员。与Advice属于q列的概念,但有着一定的区别?/SPAN>Advice只是l?/SPAN>target附加上其他的功能Q用者甚臛_以觉察不刎ͼ但是Introduction则添加了其他的功能,例如l?/SPAN>target赋予?/SPAN>lock功能Q状态等?/SPAN>1?SPAN style="FONT: 7pt 'Times New Roman'">
对于那些使用到有限外部资源的beanQ无非必要,请尽量?/SPAN>singleton2?SPAN style="FONT: 7pt 'Times New Roman'">
init-method?/SPAN>Bean创徏开始时调用Q?/SPAN>destory-method在销毁时调用.Spring自己提供?/SPAN>InitializingBeanQ?/SPAN>DisposableBean.q两个接口完成这两个功能Q一?/SPAN>Bean对象实现了这两个接口Q则无需q行M配置Q容器就?x)实现这两个功能。(当然Q这也就使得你的应用?/SPAN>Spring API捆绑C一P(j)3?SPAN style="FONT: 7pt 'Times New Roman'">
Innner BeanQ这L(fng)配置使得inner bean只能?/SPAN>wrapper bean所引用。这点在AOP中尤其有用:(x)BeanFactory只能讉KAOProxyQ而不能直接得?/SPAN>AOProxy所装?/SPAN>target object?/SPAN>4?SPAN style="FONT: 7pt 'Times New Roman'">
集合元素<list> àjava.awt.List, arrays
<set> àjava.awt.Set
<map> àjava.awt.Map
<props> àjava.awt.Properties
5?SPAN style="FONT: 7pt 'Times New Roman'">
讄I|(x)<property name="foo"><null/><property>6?SPAN style="FONT: 7pt 'Times New Roman'">
构造函数注入:(x)用于那些必须的?/SPAN>final的参数。如果构造函数的参数可能引v冲突Q可以在配置文g中给各参数加?/SPAN>type?/SPAN>7?SPAN style="FONT: 7pt 'Times New Roman'">
autowiringQ它?x)带来一定的问题Q因为无论如?/SPAN>autowiringQ都无法保证其结果一定正,很可能会(x)出现许多与预期不一致的地方?/SPAN>?/SPAN>BeanFactory中,所有的bean对象的创建都?/SPAN>lazy的,包括那些singleton bean。只?/SPAN>javabean对象必须被用的时候,才会(x)创徏该对象,才会(x)正式的解析相应的xml标记Q解析该bean?/SPAN>property{。但是在ApplicationContextQ它可以预先载入sigleton beanQ而不是直C用时才创建?/SPAN>
BeanFactory最常用的实现是XmlBeanFactoryQ蝲入“定?/SPAN>xml”文Ӟ(x)
BeanFactory factory = new XmlBeanFactory(new FileInputStream("beans.xml"));
ApplicationContext有三U实玎ͼ(x)ClassPathXmlApplicationContextQ?/SPAN>FileSystemXmlApplicationContextQ?/SPAN>XmlWebApplicationContext。其中前两者也是基于\径的Q和BeanFactory?/SPAN>xml文g定位方式一致?/SPAN>
ApplicationContext context =new FileSystemXmlApplicationContext("c:/foo.xml");
ApplicationContext context = new ClassPathXmlApplicationContext("foo.xml");
BeanFactory理Bean对象的生命周期:(x)
1?SPAN style="FONT: 7pt 'Times New Roman'">
使用构造函数创?/SPAN>Bean对象2?SPAN style="FONT: 7pt 'Times New Roman'">
Bean对象autowire被执?/SPAN>3?SPAN style="FONT: 7pt 'Times New Roman'">
Bean对象调用各项setXXXҎ(gu)4?SPAN style="FONT: 7pt 'Times New Roman'">
如果?/SPAN>Bean实现?/SPAN>BeanNameAware接口Q则调用该对象的setBeanName()Ҏ(gu)Q设|其IDQ已l在xml配置文g中写好了Q?/SPAN>5?SPAN style="FONT: 7pt 'Times New Roman'">
如果?/SPAN>Bean实现?/SPAN>BeanFactoryAware接口Q则调用该对象的setBeanFactory()Ҏ(gu)Q传?/SPAN>BeanFactory对象自n6?SPAN style="FONT: 7pt 'Times New Roman'">
如果已经配置?/SPAN>BeanPostProcessorQ那么调?/SPAN>BeanPostProcessors?/SPAN>pre-ProcessBeforeInitialization()Ҏ(gu)Q对该Bean对象q行处理Q?/SPAN>
7?SPAN style="FONT: 7pt 'Times New Roman'">
如果?/SPAN>bean自定义了init()Ҏ(gu)Q那么调用此Ҏ(gu)8?SPAN style="FONT: 7pt 'Times New Roman'"> 如果已经配置?/SPAN>BeanPostProcessor
Q那么调用该BeanPostProcessors?/SPAN>postProcessBeforeInitialization()Ҏ(gu)Q对该Bean对象q行处理
9?SPAN style="FONT: 7pt 'Times New Roman'">
正常使用10?SPAN style="FONT: 7pt 'Times New Roman'">
pȝ销毁,如果?/SPAN>bean对象实现?/SPAN>DisposableBean接口Q则调用?/SPAN>destory()Ҏ(gu)Q?/SPAN>11?SPAN style="FONT: 7pt 'Times New Roman'">
最后调用用户在配置文g中编写的destroy-method
整个Web应用分ؓ(f)四部?/SPAN>
1?SPAN style="FONT: 7pt 'Times New Roman'"> 单独?/SPAN>DAOQ负责数据访问,执行CUID(create, update, insert ,delete)Q?SPAN style="COLOR: red">完成O/R映射。不涉及(qing)M的其他逻辑Q仅执行q以上的操作Q如果有唯一性检查、事务也不需要做。(可以在数据库端加一?/SPAN>trigger,constraintQ?SPAN style="COLOR: red">该层需要定?/SPAN>DAO接口Q?/SPAN>DAO实现(hibernateQ?/SPAN>ibaitsQ?/SPAN>JDBC{?/SPAN>)?/SPAN>
2?SPAN style="FONT: 7pt 'Times New Roman'"> 单的Logic ObjectQ?/SPAN>Java BeanQ,data field+setter+getter+Other LogicQ可以将一些共有的操作提取到父cMQ减代码?/SPAN>
3?SPAN style="FONT: 7pt 'Times New Roman'"> Business SeviceQ实C务逻辑Q在此?/SPAN>DAO?/SPAN>Logic Object完成业务操作?/SPAN>q里当用到DAOӞ只需?/SPAN>IOC注入Q真实对象由外界Q?/SPAN>Web容器调用Spring容器Q注入?/SPAN>
4?SPAN style="FONT: 7pt 'Times New Roman'"> ~写ActionQ将用户界面的操作映到Busibess service?/SPAN>
使用Spring MVC的具体配|:(x)
1?/SPAN>?/SPAN>web.xml?/SPAN>, 增加dispatcher的定义,配置?/SPAN>URL Mapping分发用户调用?/SPAN>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
~写相应?/SPAN>action-servlet.xml
2、如果用了多个context文gQ?/SPAN>Spring的配|文Ӟ(j)Q则需要在Web.xml中进行配|,具体如下Q?/SPAN>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext1.xml
/WEB-INF/applicationContext2.xml
</param-value>
</context-param>
其位|在?/SPAN>sitemesh filter”之后,但是?/SPAN>filter-mapping之前?/SPAN>
3. 增加ContextLoaderListener.
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
对照了Spring in action,那个讲的更好哦。从spring的基开始讲P很不错?/P>
java代码: |
<bean id="someObjectProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>ISomeInterface</value> </property> <property name="target"> <ref bean="someObject"/> </property> <property name="interceptorNames"> <list> <value>lockMixinAdvisor</value> </list> </property> </bean> |
java代码: |
<bean id="someObjectProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> |
java代码: |
ISomeInterface someObjectProxy = (ISomeInterface) context .getBean("someObjectProxy"); |
注意Q这里返回的是ISomeInterface Q而且q个someObjectProxy 对象已经h了ILockQISomeInterface 的功能,q且在行现的完全和ISomeInterface 一致?
如果Spring的代码是预编译的Q那可以产生stub之类的,可这里是怎么实现的,人奇怪哦Q谁能解释一下么Q?
{案 Q?http://www.javajia.com/article.php?id=919
只是在这上面再封装的完美|了Q好好研Idynamic proxy的实现吧?/P>
此外Q还有这一D哦 Q)(j)
AOP的作用可以简单如下所_(d)(x)“在一个组件的前后加上一些固定的内容。?抛开AOP不说Q我们自己如果想要写q东西,无非两种方式Q一个是proxy实现Q然后在proxy的前后添加内容;q有一U就是template实现?
所以在我看来,数据库层的模板其实也是一U“AOP”?不知道有没hҎ(gu)有些意见和评qͼ
6、非常好的一个功能,在Spring Beans那个H口中添加好你的Spring配置文g之后Q在其中右键你的配置文gQ选择“show graph”,it's such a wonderful function~~~~
在线安装地址Q? http://springframework.sourceforge.net/spring-ide/eclipse/updatesite/.
注意哦,在安装的时候,一定要选“Spring framework?然后才可以装“Spring IDE?是Beans Configuration Support啦?