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,最好還是多看看源碼,開源就是好啊!