??xml version="1.0" encoding="utf-8" standalone="yes"?>
]]>
NamespaceHandlerResolverQ接口)
由DefaultBeanDefinitionDocumentReader使用Q用于定位NamespaceHandlerQ指定特定的命名I间uri
实现c:(x)
DefaultNamespaceHandlerResolver
通过map 保存所有的对应关系
默认使用spring.handlers文g来保存所有的handlers
可以定义其他的location 如:(x)
String location = "org/springframework/beans/factory/xml/support/customNamespace.properties";
NamespaceHandlerResolver resolver = new DefaultNamespaceHandlerResolver(getClass().getClassLoader(), location);
NamespaceHandlerQ接口)
基础接口Q用于DefaultBeanDefinitionDocumentReader处理自定义命名空间?br /> Ҏ(gu)Q?br /> void init();
由DefaultBeanDefinitionDocumentReader调用在构造完后但在解析自定义元素前?br />
BeanDefinition parse(Element element, ParserContext parserContext);
解析指定的元素?br />
BeanDefinitionHolder decorate(Node element,
BeanDefinitionHolder definition,
ParserContext parserContext);
执行相应的修饰?br />
实现c:(x)
NamespaceHandlerSupportQ抽象类Q?/b>
主要的三个方法:(x)
protected final void registerBeanDefinitionDecorator(
String elementName,
BeanDefinitionDecorator decorator)
注册decoratorQ通过element
protected final void registerBeanDefinitionDecoratorForAttribute(
String attributeName,
BeanDefinitionDecorator decorator)
注册decoratorQ通过attr
protected final void registerBeanDefinitionParser(
String elementName,
BeanDefinitionParser parser)
注册BeanDefinitionParserQ通过element
实际的操作由具体的BeanDefinitionDecorator 或者BeanDefinitionParser 执行
BeanDefinitionDecorator(接口)
装饰相关的自定义属性?br />
AbstractInterceptorDrivenBeanDefinitionDecorator
用于注册相应的Interceptor bean 定义Q用aop代理
其他c:(x)
PluggableSchemaResolverQ用于自定义相关的schema,默认的schema 保存于spring.schemas文g?br />
可以通过覆盖resolveEntityҎ(gu)来装载相应的自定义xsd文g
主要的执行类Q?br />
XmlBeanDefinitionReader
用于处理相应的读取工作,其实主要的工作委zBeanDefinitionDocumentReader
实际的类Q就介绍到这Q下一节通过实例来说明如何定义自定义xml 元素
]]>
考虑下面的例子:(x)(?.x实现Q?br /><bean id="myTxManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<bean id="myProductService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="product.ProductService"/>
<property name="target">
<bean class="product.DefaultProductService">
<property name="productDao" ref="myProductDao"/>
</bean>
</property>
<property name="interceptorNames">
<list>
<value>myTxInterceptor</value> <!-- the transaction interceptor (configured elsewhere) -->
</list>
</property>
</bean>
<bean id="myTxInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="myTransactionManager"/>
</property>
<property name="transactionAttributeSource">
<value>
product.ProductService.increasePrice*=PROPAGATION_REQUIRED
product.ProductService.someOtherBusinessMethod=PROPAGATION_MANDATORY
</value>
</property>
</bean>
或?br />
<bean id="myProductService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="myTransactionManager"/>
</property>
<property name="target">
<ref bean="myProductServiceTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="increasePrice*">PROPAGATION_REQUIRED</prop>
<prop key="someOtherBusinessMethod">PROPAGATION_MANDATORY</prop>
</props>
</property>
</bean>
当然Q这需要每个服务接口都要声明一个事务bean Q这比较ȝQ当Ӟspring 也提供了另外一U解x?br />
采用BeanNameAutoProxyCreator 自动代理声明入口来全局声明所有的事务?br /><bean id="matchAllWithPropReq"
class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource">
<property name="transactionAttribute"><value>PROPAGATION_REQUIRED</value></property>
</bean>
<bean id="matchAllTxInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="transactionAttributeSource"><ref bean="matchAllWithPropReq"/></property>
</bean>
<bean id="autoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<idref local="matchAllTxInterceptor"/>
<idref bean="hibInterceptor"/>
</list>
</property>
<property name="beanNames">
<list>
<idref local="core-services-applicationControllerSevice"/>
<idref local="core-services-deviceService"/>
<idref local="core-services-authenticationService"/>
<idref local="core-services-packagingMessageHandler"/>
<idref local="core-services-sendEmail"/>
<idref local="core-services-userService"/>
</list>
</property>
</bean>
list中包含了所有需要实C务的服务bean
spring 2.0带来的aop变化和bean xml schema的变化,使得事务的处理变得更加的?同aop一P事务也采用两U方式来处理Q一U主要ؓ(f)xml 声明Q另外的一U也是注释的引入?br />先来看第一U情况:(x)
<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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- SessionFactory, DataSource, etc. omitted -->
<bean id="myTxManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<aop:config>
<!-- q定义了主要的切面,也就是那些接口可以用事?q里只是说执?font color="#000000">ProductService的所有方?/font>-->
<aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
</aop:config>
<!--主要的事?advice 声明事务的相兛_?->
<tx:advice id="txAdvice" transaction-manager="myTxManager">
<tx:attributes>
<tx:method name="increasePrice*" propagation="REQUIRED"/>
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<bean id="myProductService" class="product.SimpleProductService">
<property name="productDao" ref="myProductDao"/>
</bean>
</beans>
W二U方式,使用
@Transactional
注释
@Transactional
public interface FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}
xml 配置
<!-- from the file 'context.xml' -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns: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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- this is the service object that we want to make transactional -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven/>
<!-- a PlatformTransactionManager is still required -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- sourced from somewhere else -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- other <bean/> definitions here -->
</beans>
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
// do something
}
// these settings have precedence
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// do something
}
}
private static Log log = LogFactory.getLog(Logger.class);
public void entry(String message) {
log.info(message);
}
}
q里只是单的一个方法,当然实际情况可能不同?br />׃xml配置需要一个方面的实现bean
所以创Z个简单的bean Q?br />public class LogBean {
private Logger logger = new Logger();
public Object aroundLogCalls(ProceedingJoinPoint joinPoint) throws Throwable {
logger.entry("before invoke method:"
+ joinPoint.getSignature().getName());
Object object = joinPoint.proceed();
logger.entry("after invoke method:"
+ joinPoint.getSignature().getName());
return object;
}
}
q里采取单的around adviceQ其他类型的advice 基本上都差不?br />
当然有了q两个核心的日志c,需要一个测试类Q用于测试?br />public class TestBean {
public void method1() {
System.out.println("in method1");
}
public void method2() {
System.out.println("in method2");
}
}
q就是需要测试的cMQ需要记录日志的Ҏ(gu)只有两个Q这里用System.out.printlnQ只是想昄Ҏ(gu)的调用顺序?br />
然后关键的在于xml的配|了
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=" xmlns:xsi=" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:config>
<!-- expression 表示要执行的匚w表达式,q里匚w所有的publicҎ(gu)Q但是去除loggercȝ所有方法,防止无限调用-->
<aop:pointcut id="loggableCalls"
expression="execution(public * *(..)) and !execution(* org.spring.test.aop.log.Logger.*(..))"/>
<aop:aspect id="logAspect" ref="logBean">
<aop:around pointcut-ref="loggableCalls" method="aroundLogCalls"/>
</aop:aspect>
</aop:config>
<bean id="logBean" class="org.spring.test.aop.log.LogBean" />
<bean id="testBean" class="org.spring.test.aop.log.TestBean"/>
</beans>
现在写一个测试类Q?br />
public class LogXmlTest extends RootTest {
@Override
protected String getBeanXml() {
return "org/spring/test/aop/log/bean.xml";
}
public void testLog() {
TestBean bean = (TestBean) ctx.getBean("testBean");
bean.method1();
bean.method2();
}
}
public abstract class RootTest extends TestCase {
protected ApplicationContext ctx;
protected Log log = LogFactory.getLog(getClass());
protected RootTest() {
ctx = new ClassPathXmlApplicationContext(getBeanXml());
}
protected abstract String getBeanXml();
}
打印的消息如下:(x)
2006-09-17 11:08:28,203 INFO [org.spring.test.aop.log.Logger] - before invoke method:method1
in method1
2006-09-17 11:08:28,203 INFO [org.spring.test.aop.log.Logger] - after invoke method:method1
2006-09-17 11:08:28,218 INFO [org.spring.test.aop.log.Logger] - before invoke method:method2
in method2
2006-09-17 11:08:28,218 INFO [org.spring.test.aop.log.Logger] - after invoke method:method2
W二U实现方式,采用注释方式Q?br />
Logger cM?br />创徏一个LogAspectc?br />@Aspect
public class LogAspect {
private Logger logger = new Logger();
@Pointcut("execution(public * *(..))")
public void publicMethods() {
}
@Pointcut("execution(* org.spring.test.aop.log.Logger.*(..))")
public void logObjectCalls() {
}
@Pointcut("publicMethods()&&!logObjectCalls()")
public void loggableCalls() {
}
@Around("loggableCalls()")
public Object aroundLogCalls(ProceedingJoinPoint joinPoint) throws Throwable {
logger.entry("before invoke method:"
+ joinPoint.getSignature().getName());
Object object = joinPoint.proceed();
logger.entry("after invoke method:"
+ joinPoint.getSignature().getName());
return object;
}
}
配置文gq单多?br /><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=" xmlns:xsi=" xmlns:aop=" xsi:schemaLocation="
http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
<aop:aspectj-autoproxy/>
<!-- 或者用以下定?br />
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
-->
<bean id="logAspect" class="org.spring.test.aop.log.LogAspect"/>
<bean id="testBean" class="org.spring.test.aop.log.TestBean"/>
</beans>
试c:(x)
跟上面的差不?br />把xml文g换掉p
打印的方式差不多
个hq是比较喜欢W二U实现?/p>
<aop:aspectj-autoproxy/>
或?br />在xml中加?br /><bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
声明 aspect
<bean id="myAspect" class="org.xyz.NotVeryUsefulAspect">
<!-- configure properties of aspect here as normal -->
</bean>
package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsefulAspect {
}
声明
pointcut
@Pointcut("execution(* transfer(..))")
public void transfer() {}
声明
advice
Before advice:
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
After returning advice:
@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
或?/span>
@AfterReturning(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
returning="retVal")
public void doAccessCheck(Object retVal) {
// ...
}
After throwing adviceQ?o:p>
@AfterThrowing("SystemArchitecture.dataAccessOperation()")
public void doRecoveryActions() {
// ...
}
或?/span>
@AfterThrowing(
pointcut=" SystemArchitecture.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ...
}
After (finally) adviceQ?o:p>
@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doReleaseLock() {
// ...
}
Around adviceQ?o:p>
@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doBasicProfiling(
ProceedingJoinPoint
pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
Advice parametersQ?o:p>
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation() &&" +
"args(account,..)"
)
public void validateAccount(Account account) {
// ...
}
声明参数名称Q?/span>
@Before(
value="com.xyz.lib.Pointcuts.anyPublicMethod() && " +
"@annotation(auditable)",
argNames="auditable"
)
public void audit(Auditable auditable) {
AuditCode code = auditable.value();
// ...
}
Advice 排序Q?o:p>
一般以声明的方法次序ؓ(f)先后
不同?/span>
Advice
Q通过实现
Ordered
接口Q来排序
用于引入新的接口
@Aspect
public class UsageTracking {
@DeclareParents(value="com.xzy.myapp.service.*+",
defaultImpl=DefaultUsageTracked.class)
public static UsageTracked mixin;
@Before("com.xyz.myapp.SystemArchitecture.businessService() &&" +
"this(usageTracked)")
public void recordUsage(UsageTracked usageTracked) {
usageTracked.incrementUseCount();
}
}
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
xpointcut
<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
</aop:config>
xadvice
Before adviceQ?/span>
<aop:aspect id="beforeExample" ref="aBean">
<aop:before
pointcut-ref="dataAccessOperation"
method="doAccessCheck"/>
</aop:aspect>
After returning advice:
<aop:aspect id="afterReturningExample" ref="aBean">
<aop:after-returning
pointcut-ref="dataAccessOperation"
method="doAccessCheck"/>
...
</aop:aspect>
或者带有返回参?/span>
<aop:aspect id="afterReturningExample" ref="aBean">
<aop:after-returning
pointcut-ref="dataAccessOperation"
returning="retVal"
method="doAccessCheck"/>
...
</aop:aspect>
After throwing adviceQ?/span>
<aop:aspect id="afterThrowingExample" ref="aBean">
<aop:after-throwing
pointcut-ref="dataAccessOperation"
method="doRecoveryActions"/>
...
</aop:aspect>
或者带有throwing
<aop:aspect id="afterThrowingExample" ref="aBean">
<aop:after-throwing
pointcut-ref="dataAccessOperation"
throwing="dataAccessEx"
method="doRecoveryActions"/>
...
</aop:aspect>
After (finally) adviceQ?/span>
<aop:aspect id="afterFinallyExample" ref="aBean">
<aop:after
pointcut-ref="dataAccessOperation"
method="doReleaseLock"/>
...
</aop:aspect>
Around adviceQ?/span>
<aop:aspect id="aroundExample" ref="aBean">
<aop:around
pointcut-ref="businessService"
method="doBasicProfiling"/>
...
</aop:aspect>
Advice parametersQ?/span>
<aop:before
pointcut="Pointcuts.anyPublicMethod() and @annotation(auditable)"
method="audit"
arg-names="auditable"/>
对于引入接口Q?a name="_Toc144432334">IntroductionsQ:(x)
<aop:aspect id="usageTrackerAspect" ref="usageTracking">
<aop:declare-parents
types-matching="com.xzy.myapp.service.*+",
implement-interface="UsageTracked"
default-impl=" service.tracking.DefaultUsageTracked"/>
<aop:before
pointcut="com.xyz.myapp.SystemArchitecture.businessService()
and this(usageTracked)"
method="recordUsage"/>
</aop:aspect>