AOP是一个比较通用的概念,主要关注的内容用一句话来说就是"如何使用一个对象代理另外一个对象",不同的框架会有不同的实现,Aspectj 是在编译期就绑定了代理对象与被代理对象的关系,而Spring是在运行期间通过动态代理的方式来现实代理对象与被代理对象的绑定.具体的概念可以参考各自的文档:
Spring: http://docs.spring.io/spring/docs/3.2.1.RELEASE/spring-framework-reference/html/aop.html#aop-introduction
Aspecctj:http://eclipse.org/aspectj/
接下来仍然通过一个综合的例子来说明使用XML的方式如何使用Spring AOP
入口类
package com.eric.introduce; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.eric.introduce.aop.Contestant; import com.eric.introduce.aop.IUser; import com.eric.introduce.aop.Worker; import com.eric.introduce.di.Performer; public class AOPCaller { private static final String CONFIG = "com/eric/introduce/aop/aop.xml"; private static ApplicationContext context = new ClassPathXmlApplicationContext( CONFIG); public static void main(String[] args) { // simpleAOPCase(); // arguementAOPTest(); demoDeclareParents(); } /** * 演示了aop after-returning/before/after-throwing/around * NOTE:如果在performer()方法执行的过程中产生异常且在around的方法中捕获了异常 * ,则after-throwing对应的方法不会被执行 */ public static void simpleAOPCase() { // 必须是接口类型,否则会包ClassCastException Performer eric = (Performer) context.getBean("performer1"); eric.performer(); } /** * 演示:aop 参数的传递方法 * 在用户开户成功后,发送一条问候短信,通过userName参数把用户名发给SMSGreeting */ public static void arguementAOPTest() { IUser user = (IUser) context.getBean("user"); user.openAccount("Eric"); } /** * 演示aop:declare-parents 的用法 * 在不改变源码的情况下,让Worker的子类包含Contestant接口的功能. * getBean("worker")返回的对象即可以强转成Worker也可以强转成Contestant,而该对象只是实现了Worker接口 */ public static void demoDeclareParents() { Worker worker = (Worker) context.getBean("worker"); worker.hardWord(); ((Contestant) worker).receiveAward(); Contestant worker2 = (Contestant) context.getBean("worker"); worker2.receiveAward(); ((Worker) worker2).hardWord(); } }
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" 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-3.0.xsd"> <bean id="audience" class="com.eric.introduce.aop.Audience" /> <bean id="performer1" class="com.eric.introduce.di.InstrumentPerformer" /> <bean id="user" class="com.eric.introduce.aop.MobileUser" /> <bean id="smsgreeting" class="com.eric.introduce.aop.SMSGreeting" /> <!-- 为了使用aop:declare-parents特性,ITWorker必须声明为Worker接口的子类 --> <bean id="worker" class="com.eric.introduce.aop.ITWorker" /> <aop:config> <aop:aspect ref="audience"> <aop:pointcut expression="execution(* com.eric.introduce.di.InstrumentPerformer.performer(..))" id="performance" /> <aop:before method="takeSeat" pointcut-ref="performance" /> <aop:before method="turnOffCell" pointcut-ref="performance" /> <aop:after-returning method="applaud" pointcut-ref="performance" /> <aop:after-throwing method="demandRefund" pointcut-ref="performance" /> <aop:around method="calculateTime" pointcut-ref="performance" /> </aop:aspect> <aop:aspect ref="smsgreeting"> <aop:pointcut expression="execution(* com.eric.introduce.aop.MobileUser.openAccount(String)) and args(userName)" id="openaccount" /> <!-- 在用户开户成功后,发送一条问候短信,通过userName参数把用户名发给SMSGreeting --> <aop:after-returning method="greeting" pointcut-ref="openaccount" arg-names="userName" /> </aop:aspect> <aop:aspect> <!-- 在不改变源码的情况下,让Worker的子类包含Contestant接口的功能 --> <!-- com.eric.introduce.aop.Worker+ 说明针对Worker的子类有效 --> <aop:declare-parents types-matching="com.eric.introduce.aop.Worker+" implement-interface="com.eric.introduce.aop.Contestant" default-impl="com.eric.introduce.aop.GraciousContestant" /> </aop:aspect> </aop:config> </beans>
其他相关类
after-returning/before/after-throwing/around 相关
package com.eric.introduce.aop; import org.aspectj.lang.ProceedingJoinPoint; /** * 观众类 * * @author Eric * */ public class Audience { public void takeSeat() { System.out.println("AOP: Enter, take seat"); } public void turnOffCell() { System.out.println("AOP: Show will start, turn off cell"); } public void applaud() { System.out.println("AOP: Nice performance, applaud"); } public void demandRefund() { System.out.println("AOP: Bad Performance, Return money"); } public void calculateTime(ProceedingJoinPoint joinPoint) { long begintime = System.currentTimeMillis(); try { joinPoint.proceed(); } catch (Throwable exception) { System.out.println("Live Show has Exception"); } long end = System.currentTimeMillis(); System.out.println("AOP aRound: Spent Time:" + (end - begintime)); } } package com.eric.introduce.di; import java.util.List; import java.util.Properties; /** * 定义一个表演者,这个表演者实现Performer接口 * * @author Eric * */ public class InstrumentPerformer implements Performer { /** * demo injection value */ private String name; /** * demo injection Ref Bean */ private Instrument instrument; /** * demo injection original typ */ private int age; /** * demo injection internal bean */ private Instrument privateInstrument; /** * demo injection List/Set/Array */ private List<Fruit> favFruit; /** * demo injection Properties/Map */ private Properties properties; @Override public void performer() { System.out.println("Normal Instrument:"); try { Thread.sleep(1999); } catch (InterruptedException e) { e.printStackTrace(); } instrument.play(); System.out.println("Special Instrument:"); privateInstrument.play(); } @Override public void eatFruit() { for (Fruit fruit : favFruit) { fruit.eat(); } } @Override public void printProperties() { System.out.println(name + " Properties: "); for (Object key : properties.keySet()) { System.out.println(key + " " + properties.getProperty((String) key) + " "); } } public String getName() { return name; } public void setName(String name) { this.name = name; } public Instrument getInstrument() { return instrument; } public void setInstrument(Instrument instrument) { this.instrument = instrument; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Instrument getPrivateInstrument() { return privateInstrument; } public void setPrivateInstrument(Instrument privateInstrument) { this.privateInstrument = privateInstrument; } public List<Fruit> getFavFruit() { return favFruit; } public void setFavFruit(List<Fruit> favFruit) { this.favFruit = favFruit; } public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } }
aop:declare-parents 相关
package com.eric.introduce.aop; /** * 主要用来演示declare-parents * * @author Eric * */ public interface Contestant { public void receiveAward(); } package com.eric.introduce.aop; public class GraciousContestant implements Contestant { @Override public void receiveAward() { System.out.println("receiveAward was executed"); } } package com.eric.introduce.aop; public class ITWorker implements Worker { public void hardWord() { System.out.println("Worker is working hard!"); } } package com.eric.introduce.aop; /** * 主要用来演示declare-parents * * @author Eric * */ public interface Worker { public void hardWord(); }
参数相关
package com.eric.introduce.aop; /** * 定义一个问候接口 * @author Eric * */ public interface IGreeting { /** * 定义了问候方法,但检测到有用户开户时,通过AOP机制自动发送问候短信 * @param name */ public void greeting(String name); } package com.eric.introduce.aop; public interface IUser { /** * 开户操作 * @param name */ public void openAccount(String name); } package com.eric.introduce.aop; public class MobileUser implements IUser { @Override public void openAccount(String name) { System.out.println("Register Succssful:" + name); } } package com.eric.introduce.aop; /** * 短信問候 * @author Eric * */ public class SMSGreeting implements IGreeting { @Override public void greeting(String name) { System.out.println("Dear " + name + " Welcome to use CMCC"); } }