Spring
中的
AOP
簡單使用
???
??? AOP
作為
Spring
這個輕量級的容器中很重要的一部分,得到越來越多的關注,
Spring
的
Transaction
就是用
AOP
來管理的,今天就通過簡單的例子來看看
Spring
中的
AOP
的基本使用方法。
?
?
首先確定將要
Proxy
的目標,在
Spring
中默認采用
JDK
中的
dynamic proxy
,它只能夠實現接口的代理,如果想對類進行代理的話,需要采用
CGLIB
的
proxy
。顯然,選擇
“
編程到接口
”
是更明智的做法。
?
下面是將要代理的接口:
public interface FooInterface {
??? public void printFoo();
??? public void dummyFoo();
}
以及其一個簡單的實現:
public class FooImpl implements FooInterface {
??? public void printFoo() {
??????? System.out.println("In FooImpl.printFoo");
??? }
??? public void dummyFoo() {
??????? System.out.println("In FooImpl.dummyFoo");
??? }
}
?
接下來創建一個
Advice
,在
Spring
中支持
Around,Before,After returning
和
Throws
四種
Advice
,這里就以簡單的
Before Advice
舉例:
?
public class PrintBeforeAdvice implements MethodBeforeAdvice {
??? public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
??????? System.out.println("In PrintBeforeAdvice");
??? }
}
?
有了自己的
business interface
和
advice
,剩下的就是如何去裝配它們了,首先利用
ProxyFactory
以編程方式實現,如下:
?
public class AopTestMain {
??? public static void main(String[] args) {
??????? FooImpl fooImpl = new FooImpl();
??????? PrintBeforeAdvice myAdvice = new PrintBeforeAdvice();
?????
?????? ?ProxyFactory factory = new ProxyFactory(fooImpl);
??????? factory.addBeforeAdvice(myAdvice);
??????? FooInterface myInterface = (FooInterface)factory.getProxy();
??????? myInterface.printFoo();
??????? myInterface.dummyFoo();
??? }
}
?
?
現在執行程序,神奇的結果就出現了:
?
? In PrintBeforeAdvice
? In FooImpl.printFoo
? In PrintBeforeAdvice
? In FooImpl.dummyFoo
?
??
雖然這樣能體會到
Spring
中
AOP
的用法,但這決不是值得推薦的方法,既然使用了
Spring
,在
ApplicationContext
中裝配所需要
的
bean
才是最佳策略,實現上面的功能只需要寫個簡單的
applicationContext
就可以了,如下:
?
? <?xml version="1.0" encoding="UTF-8"?>
? <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
??? "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
??? <description>The aop application context</description>
??? <bean id="fooTarget" class="FooImpl"/>
??? <bean id="myAdvice" class="PrintBeforeAdvice"/>
?? ?<bean id="foo" class="org.springframework.aop.framework.ProxyFactoryBean">
???? <property name="proxyInterfaces">
?????? <value>FooInterface</value>
???? </property>
?????<property name="target">
?????? <ref local="fooTarget"/>
???? </property>
???? <property name="interceptorNames">
?????? <list>
???????? <value>myAdvice</value>
?????? </list>
???? </property>
??? </bean>
</beans>
?
??
當然,
main
中的代碼也要進行相應的修改:
????
public static void main(String[] args) {
??? ClassPathXmlApplicationContext context = new?
?????????????ClassPathXmlApplicationContext("applicationContext.xml");
??? FooInterface foo = (FooInterface)context.getBean("foo");
??? foo.printFoo();
??? foo.dummyFoo();
}
?
??
現在運行一下,結果將和上面的運行結果完全一樣,這樣是不是更優雅?當需要更改實現時,只需要修改配置文件就可以了,程序中的代碼不需任何改動。
?
??
但是,這時候會發現被
proxy
的
object
中的所有方法調用時都將運行
advice
中的
before
,這顯然不能滿足絕大多數情況下的需要,此時,只
需借用
Advisor
就可以了,當然要在
Advisor
中利用
pattern
設置好哪些方法需要
advice
,更改
applicationContext
如下:
?
? <?xml version="1.0" encoding="UTF-8"?>
? <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
??? "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
??? <description>The springeva application context</description>
?? ?<bean id="fooTarget" class="FooImpl"/>
??? <bean id="printBeforeAdvice" class="PrintBeforeAdvice"/>
??? <bean id="myAdvisor"
????????? class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
????? <property name="advice">
??????? <ref local="printBeforeAdvice"/>
????? </property>
????? <property name="pattern">
??????? <value>.*print.*</value>
????? </property>
??? </bean>
??? <bean id="foo" class="org.springframework.aop.framework.ProxyFactoryBean">
????? <property name="proxyInterfaces">
????????<value>FooInterface</value>
????? </property>
????? <property name="target">
??????? <ref local="fooTarget"/>
????? </property>
????? <property name="interceptorNames">
??????? <list>
????????? <value>myAdvisor</value>
??????? </list>
??????</property>
??? </bean>
</beans>
?
???
主程序不需進行任何修改,運行結果已經變樣了
?? In PrintBeforeAdvice
??? In FooImpl.printFoo
??? In FooImpl.dummyFoo
?
??
至此,應該已經理解了
Spring
中
AOP
的使用方法,當然
Spring
中
AOP
最重要的應用是
Transaction Manager
,舉個這方面的
applicationContext
例子看看:
?
? <?xml version="1.0" encoding="UTF-8"?>
? <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "spring-beans.dtd">
<beans>
??? <bean id="propertyConfigurer"???
???????? class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
????? <property name="location">
??????? <value>/WEB-INF/jdbc.properties</value>
??????</property>
?? ?</bean>
??? <bean id="dataSource"
????????? class="org.springframework.jdbc.datasource.DriverManagerDataSource">
????? <property name="driverClassName">
??????? <value>${jdbc.driverClassName}</value>
????? </property>
??????<property name="url">
??????? <value>${jdbc.url}</value>
????? </property>
????? <property name="username">
??????? <value>${jdbc.username}</value>
????? </property>
????? <property name="password">
??????? <value>${jdbc.password}</value>
????? </property>
??? </bean>
?? ?<bean id="sessionFactory"
????????? class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
????? <property name="dataSource">
??????? <ref local="dataSource"/>
????? </property>
????? <property name="mappingResources">
??????? <value>smartmenu.hbm.xml</value>
????? </property>
????? <property name="hibernateProperties">
??????? <props>
????????? <prop key="hibernate.dialect">${hibernate.dialect}</prop>
??????? </props>
????? </property>
??? </bean>
?
??? <bean id="transactionManager"???????
????????? class="org.springframework.orm.hibernate.HibernateTransactionManager">
????? <property name="sessionFactory">
??????? <ref local="sessionFactory"/>
????? </property>
??? </bean>
??? <bean id="smartmenuTarget" class="SmartMenuHibernate">
????? <property name="sessionFactory">
??????? <ref local="sessionFactory"/>
????? </property>
??? </bean>
?? ?<bean id="smartMenu"
??????? class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
????? <property name="transactionManager">
??????? <ref local="transactionManager"/>
????? </property>
????? <property name="target">
??????? <ref local="smartmenuTarget"/>
????? </property>
????? <property name="transactionAttributes">
??????? <props>
????????? <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
????????? <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
??????? </props>
????? </property>
??? </bean>
? </beans>
?
?
要想徹底理解
Spring
的
AOP
,最好還是多看看源碼,開源就是好啊!