静态代理与动态代理:
代理模式的定义是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理设计模式可以在不改变原始代码
静态代理的实现:
ISendBook接口
public interface ISendBook { public void sendBook(); }
DangDang类,继承ISendBook接口:
public class DangDang implements ISendBook{ @Override public void sendBook() { // TODO Auto-generated method stub System.out.println("当当网-书籍部门,将书送到指定地址的客户手中"); } }
SFSendBookProxy类,继承ISendBook的另外一个接口
public class SFSendBookProxy implements ISendBook{ public ISendBook sendBook; public SFSendBookProxy(ISendBook sendBook){ super(); this.sendBook = sendBook; } @Override public void sendBook() { // TODO Auto-generated method stub System.out.println("顺丰接收书籍"); sendBook.sendBook(); System.out.println("顺丰书籍已送达"); } }
AopTest类
public class AopTest { public static void main(String[] args) { // TODO Auto-generated method stub ISendBook sendBook = new SFSendBookProxy(new DangDang()); sendBook.sendBook(); } }
运行结果:
顺丰接收书籍 当当网-书籍部门,将书送到指定地址的客户手中 顺丰书籍已送达
上述代码实现了静态的代理,在改变原有的DangDang类的同时,对其方法进行了增加内容/功能。但这种代理有个致命的缺点,就是要创建一个类,并且这个类要继承与要增加增加功能的类一致的接口,由于与接口绑死,不利于扩张。因此有了下面的动态代理。
接口与DangDang类保持不变,创建一个类继承InvocationHandler接口:
public class SendBookInvocationHandler implements InvocationHandler{ private Object object; public SendBookInvocationHandler(Object object){ super(); this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub System.out.println("顺丰接收书籍"); Object returnValue = method.invoke(object,args); System.out.println("顺丰配出书籍"); return returnValue; } }
更改AopTest类main方法的内容:
public static void main(String[] args) { DangDang dangdang = new DangDang(); ISendBook sendBook = (ISendBook) Proxy.newProxyInstance(AopTest.class.getClassLoader(), dangdang.getClass().getInterfaces(),new SendBookInvocationHandler(dangdang)); sendBook.sendBook(); }
运行结果:
顺丰接收书籍 当当网-书籍部门,将书送到指定地址的客户手中 顺丰配出书籍
同样实现了对DangDang的sendBook方法增强了内容/功能。但这种方式仅仅只用继承唯一指定的接口便可以实现,而不是要继承与类一致的接口。有利于扩展。
尽管原生态SDK的动态代理能实现功能,但还是不太方便,并且每个程序员的写法会不同,不利于代码风格的一致性与后期维护,因此使用了Spring框架对动态代理进行了封装,方便与维护。
1. 方法前通知要实现MethodBeforeAdvice接口
2. 方法后通知要实现AfterReturningAdvice接口
3. 方法环绕通知要实现MethodInterceptor接口
4. 异常处理通知要实现 ThrowsAdvice接口
对上述进行Spring进行动态代理:
ISendBook接口以及DangDang类不用修改
添加AfterSentBook类:该类继承了AfterReturningAdvice接口
public class AfterSentBook implements AfterReturningAdvice{ //Object arg0:返回值 //Method arg1:方法对象 //Object[] arg2:参数 //Object arg3:原始目标被功能增强的对象 @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { // TODO Auto-generated method stub System.out.println("AftrSentBook信息,返回值:"+arg0+",方法名称:"+arg1+",方法参数个数:"+arg2.length+ ",原始对象:"+arg3); } }
添加BeforeSendBook类:该类继承了MethodBeforAdvice接口
public class BeforeSendBook implements MethodBeforeAdvice{ //Method arg0 :方法对象 //Object[] arg1: 方法的参数值 //Object arg2:原始目标被功能增强的对象 @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { // TODO Auto-generated method stub System.out.println("BeforeSendBook信息,方法名称="+arg0.getName()+",参数个数:"+arg1.length+",原始对象:"+arg2); } }
该类继承了MethodTnterceptor接口
public class RoundSentBook implements MethodInterceptor{ /** * MethodInvocation arg0:类的对象,可以通过此对象,调用以下的方法 * getArguments(): 获取参数 * getMethod(): 获取方法对象 * getThis(): 原始目标被功能增强的对象 * proceed():调用原始目标对象的指定Method方法,并返回原始目标对象 * */ @Override public Object invoke(MethodInvocation arg0) throws Throwable { // TODO Auto-generated method stub System.out.println("MethodInterceptor begin信息,方法名称="+arg0.getMethod().getName()+ "参数个数:"+arg0.getArguments()+",原始对象:"+arg0.getThis()); Object object = arg0.proceed(); System.out.println("MethodInterceptor end信息,方法名称="+arg0.getMethod().getName()+ "参数个数:"+arg0.getArguments()+",原始对象:"+arg0.getThis()); return object; } }
xml配置文件:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="dangdang" class="Spring.DangDang"></bean> <bean id="before" class="Spring.BeforeSendBook"></bean> <bean id="after" class="Spring.AfterSentBook"></bean> <bean id="round" class="Spring.RoundSentBook"></bean> <bean id="error" class="Spring.My_ThrowsAdvice"></bean> <!-- --> <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interfaces"> <list> <value>Spring.ISendBook</value> </list> </property> <property name="target" ref="dangdang"></property> <property name="interceptorNames"> <list> <value>round</value> <value>before</value> <value>after</value> </list> </property> </bean> </beans>
AopTest类:
public class AopTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("aop-applicationContext.xml");
ISendBook sendBook = (ISendBook)context.getBean("proxy");
sendBook.sendBook();
}
}
运行结果如下:
MethodInterceptor begin信息,方法名称=sendBook参数个数:[Ljava.lang.Object;@63e2203c,原始对象:Spring.DangDang@1efed156
BeforeSendBook信息,方法名称=sendBook,参数个数:0,原始对象:Spring.DangDang@1efed156
当当网-书籍部门,将书送到指定地址的客户手中
AftrSentBook信息,返回值:null,方法名称:public abstract void Spring.ISendBook.sendBook(),方法参数个数:0,原始对象:Spring.DangDang@1efed156
MethodInterceptor end信息,方法名称=sendBook参数个数:[Ljava.lang.Object;@6737fd8f,原始对象:Spring.DangDang@1efed156
我们可以看到Spring对动态代理进行了封装,但是这种方式一个通用业务需要创建4个类,方法执行前,方法执行后,方法环绕,以及出现异常的情况,假设如果有很多个通用业务,那么就需要创建4*对应通用业务数,尽管有效的对动态代理进行了有效的封装,但如果通用业务多的话,管理起来还是比较复杂,因此Spring 推出了AOP的方式来实现。
Spring的AOP:
要知道,Spring的AOP技术原理就是基于代理设计模式的。因此当Spring使用AOP技术的时候,运行的效果往往与动态代理的效果是很类似,或者是是一摸一样的。
在学习AOP技术之前,首先需要了解几个概念:
1. 横切关注点
2.切面
3. 连接点
4. 切点
5. 通知:通知便是定义了在什么时机进行切莫的参数,在Spring的AOP的通知中,分为5种:
前置通知(Before):方法被调用前
后置通知(After):方法被调用后
环绕通知(Around):方法被调用之前与之后
返回通知(After-returning):方法返回了值后执行
异常处理(After-throwing):当执行方法中出现异常后触发执行
6. 织入
与DI容器/IOC技术一样,Spring实现aop技术也可以分全xml与全注解的形式。它们实现的功能都是相同的,只是编写的形式不一样。
使用xml方式 DangDang类:
public class DangDang{ boolean isGet = false; public void bookBooks(){ System.out.println("当当网-书籍部门,客户订书了"); } public void sendBook() { // TODO Auto-generated method stub System.out.println("当当网-书籍部门,将书送到指定地址的客户手中"); } public boolean isGetBook(){ System.out.println("客户是否收到书籍"); return isGet; } }
使用xml方式:AspectObject类
public class AspectObject { public void beginRun(){ System.out.println("前置通知------------"); } public void endRun(){ System.out.println("后置通知------------"); } public Object round(ProceedingJoinPoint point){ System.out.println("前"); Object returnObject = null; try { returnObject = point.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("后"); return returnObject; } @AfterReturning("execution(* Spring.DangDang.* (..))") public void afterRun(){ System.out.println("返回值通知------------"); } public void afterThrowing(){ System.out.println("异常通知------------"); } }
使用xml方式:aop-applicationConfig.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:context="http://www.springframework.org/schema/context" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="dangdang" class="Spring.DangDang"></bean> <bean id="aspectObject" class="Spring.AspectObject"></bean> <aop:config> <aop:aspect ref="aspectObject"> <aop:before method="beginRun" pointcut="execution(* Spring.DangDang.bookBooks(..))"/> <aop:after method="endRun" pointcut="execution(* Spring.DangDang.bookBooks(..))"/> <aop:around method="round" pointcut="execution(* Spring.DangDang.sendBook(..))"/> <aop:after-returning method="afterRun" pointcut="execution(* Spring.DangDang.isGetBook(..))"/> <aop:after-throwing method="afterThrowing" pointcut="execution(* Spring.DangDang.*(..))"/> </aop:aspect> </aop:config> </beans>
使用了xml方式:AopTest类
public class AopTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("aop-applicationContext.xml"); DangDang dangdang = (DangDang) context.getBean("dangdang"); dangdang.bookBooks(); System.out.println(); dangdang.sendBook(); System.out.println(); dangdang.isGetBook(); } }
运行结果如下:
前置通知------------ 当当网-书籍部门,客户订书了 后置通知------------ 前 当当网-书籍部门,将书送到指定地址的客户手中 后 客户是否收到书籍 返回值通知------------
使用注解的方式,DangDang类:
@Component(value="dangdang1")
public class DangDang{ boolean isGet = false; public void bookBooks(){ System.out.println("当当网-书籍部门,客户订书了"); } public void sendBook() { // TODO Auto-generated method stub System.out.println("当当网-书籍部门,将书送到指定地址的客户手中"); } public boolean isGetBook(){ System.out.println("客户是否收到书籍"); return isGet; } }
使用注解的方式,AspectObject类:
@Component @Aspect //必须填写,不然不知道切面要执行的执行体 public class AspectObject { @Before(value="execution(* Spring.DangDang.bookBooks(..))") public void beginRun(){ System.out.println("前置通知------------"); } @After(value="execution(* Spring.DangDang.bookBooks(..))") public void endRun(){ System.out.println("后置通知------------"); } @Around(value="execution(* Spring.DangDang.sendBook(..))") public Object round(ProceedingJoinPoint point){ System.out.println("前"); Object returnObject = null; try { returnObject = point.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("后"); return returnObject; } @AfterReturning(value="execution(* Spring.DangDang.isGetBook (..))") public void afterRun(){ System.out.println("返回值通知------------"); } @AfterThrowing(value="publicPointcut() and bean(dangdang1)") public void afterThrowing(){ System.out.println("异常通知------------"); } }
使用注解的方式,AopTest类:
@EnableAspectJAutoProxy //必须填写,如无该注解的话,AspectObject类仅仅只是一个普通的类,有该注解,AspectObject才能算的上是切面 @ComponentScan(basePackages="Spring") public class AopTest { public static void main(String[] args) { String resource = "Spring"; AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopTest.class); DangDang dangdang = (DangDang) context.getBean("dangdang1"); dangdang.bookBooks(null); System.out.println(); dangdang.sendBook(null,null); System.out.println(); dangdang.isGetBook(); } }
运行效果与使用xml方式的运行效果一致。
看到上述使用xml方式与注解方式,最主要的是execution(* Spring.DangDang.bookBooks(..))的表达式,该表达式对应的参数如下:
第一个代表的是返回值,* 代表任意的返回值
第二个代表的是指定包下的指定类下的指定方法下的指定参数,Spring.DangDang.bookBooks(..) ,代表的是Spring包下的DangDang类下的bookBooks方法,使用的是任意的bookBooks的参数。括号中代表的是对应方法的参数,每个方法的参数都不一致,因此可以用..来代替任意的参数。若想调用该类的全部方法:Spring.DangDang.*(..)
可以看到前置与后置的切点都是一致的,为了减少execution表达式,降低冗余的配置,可以将execution表达式进行全局化:
对应xml方式,改动aop-applicationConfig.xml文件:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="dangdang" class="Spring.DangDang"></bean> <bean id="aspectObject" class="Spring.AspectObject"></bean> <aop:config> <!-- 定义全局切点 --> <aop:pointcut id="pointcut1" expression="execution(* Spring.DangDang.bookBooks(..))"/> <aop:pointcut id="pointcut2" expression="execution(* Spring.DangDang.* (..))" /> <aop:aspect ref="aspectObject"> <aop:before method="beginRun" pointcut-ref="pointcut1"/> <aop:after method="endRun" pointcut-ref="pointcut1"/> <aop:around method="round" pointcut="execution(* Spring.DangDang.sendBook(..))"/> <aop:after-returning method="afterRun" pointcut="execution(* Spring.DangDang.isGetBook(..))"/> <aop:after-throwing method="afterThrowing"/> </aop:aspect> </aop:config> </beans>
修改后运行AopTest类:运行效果一致
对应注解的方式,仅改动AspectObject类:
@Component @Aspect //必须填写,不然不知道切面要执行的执行体 public class AspectObject {
@Pointcut(value="execution(* Spring.DangDang.bookBooks(..))")
public void publicPointcut(){}
@Before(value="publicPointcut()") public void beginRun(){ System.out.println("前置通知------------"); } @After(value="publicPointcut()") public void endRun(){ System.out.println("后置通知------------"); } @Around(value="execution(* Spring.DangDang.sendBook(..))") public Object round(ProceedingJoinPoint point){ System.out.println("前"); Object returnObject = null; try { returnObject = point.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("后"); return returnObject; } @AfterReturning(value="execution(* Spring.DangDang.isGetBook (..))") public void afterRun(){ System.out.println("返回值通知------------"); } @AfterThrowing(value="publicPointcut() and bean(dangdang1)") public void afterThrowing(){ System.out.println("异常通知------------"); } }
修改后运行AopTest类:运行效果一致
向切面传入参数值:
如果方法中有参数,切面类也可以接收这个参数,并可以进行预处理。在5种通知中,对于获取方法参数重要的是前置,后置与绕环的通知种类;而返回通知,是获取方法的返回值,异常通知,则是获取方法中出现的异常。
使用xml的方式,DangDang类:对方法中添加了参数
@Component(value="dangdang1") public class DangDang{ boolean isGet = false; public void bookBooks(Integer userId){ System.out.println("当当网-书籍部门,客户订书了"); } public void sendBook(Integer userId,Integer orderId) { // TODO Auto-generated method stub System.out.println("当当网-书籍部门,将书送到指定地址的客户手中"); } public boolean isGetBook(){ System.out.println("客户是否收到书籍"); return isGet; } }
使用xml的方式,AspectObject类:
public class AspectObject {
//切面类的方法参数要与对应方法的参数(包括参数的数据类型以及参数名)一致,从而可以获取方法的参数 public void beginRun(Integer userId){ if(userId != null){ System.out.println("客户已登录,userId号为:"+userId); }else{ System.out.println("客户未登陆,已让客户去登录"); userId = 12; System.out.println("客户登录成功,userId号为:"+userId); } } public Integer endRun(Integer userId){ Integer orderId = 120; System.out.println("已生成订单,订单号为:"+orderId); return orderId; } public Object round(ProceedingJoinPoint point,Integer userId,Integer orderId){ System.out.println("前,userId:"+userId+",orderId:"+orderId); Object returnObject = null; try { returnObject = point.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("后,userId:"+userId+",orderId:"+orderId); return returnObject; } public void afterRun(boolean isGet){ System.out.println("返回值通知------------"); if(isGet){ System.out.println("客户已收到"); }else{ System.out.println("客户未收到"); } }
public void afterThrowing(Throwable t){ System.out.println("异常通知------------"); System.out.println("aopThrowMethod t="+t.getMessage()); } }
使用xml方式,aop-applicationConfig.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:context="http://www.springframework.org/schema/context" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="dangdang1" class="Spring.DangDang"></bean> <bean id="aspectObject" class="Spring.AspectObject"></bean> <aop:config> <!-- 定义全局切点 --> <!-- 全部变量,execution表达式中方法名后面的括号填写参数的数据类型,按照方法的参数顺序填写, 在exectution表达式后跟着的是对应方法参数的值,注意的是,一定要用and来连接起来,否则会出错 --> <aop:pointcut id="pointcut1" expression="execution(* Spring.DangDang.bookBooks(Integer)) and args(userId)"/> <aop:pointcut id="pointcut2" expression="execution(* Spring.DangDang.* (..))" /> <aop:aspect ref="aspectObject"> <aop:before method="beginRun" pointcut-ref="pointcut1"/> <aop:after method="endRun" pointcut-ref="pointcut1"/> <aop:around method="round" pointcut="execution(* Spring.DangDang.sendBook(Integer,Integer)) and args(userId,orderId)"/> <aop:after-returning method="afterRun" pointcut="execution(* Spring.DangDang.isGetBook(..))" returning="isGet"/> <-- 返回通知,获取方法的返回值,returning的值与方法返回的值名称是一致的-->
<-- 异常通知,获取方法执行中的异常状态,throwing的方法 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut2" throwing="t"/> </aop:aspect> </aop:config> </beans>
AopTest类:
public class AopTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("aop-applicationContext.xml");
DangDang dangdang = (DangDang) context.getBean("dangdang1");
dangdang.bookBooks(1);
System.out.println();
dangdang.sendBook(1,120);
System.out.println();
dangdang.isGetBook();
}
}
运行效果如下:
客户已登录,userId号为:1
当当网-书籍部门,客户订书了
已生成订单,订单号为:120
前,userId:1,orderId:120
当当网-书籍部门,将书送到指定地址的客户手中
后,userId:1,orderId:120
客户是否收到书籍
返回值通知------------
客户未收到
使用注解的方式,DangDang类:
@Component(value="dangdang1")
public class DangDang{
boolean isGet = false;
public void bookBooks(Integer userId){
System.out.println("当当网-书籍部门,客户订书了");
}
public void sendBook(Integer userId,Integer orderId) {
// TODO Auto-generated method stub
System.out.println("当当网-书籍部门,将书送到指定地址的客户手中");
}
public boolean isGetBook(){
System.out.println("客户是否收到书籍");
return isGet;
}
}
使用注解的方式,AspectObject类:
@Component
@Aspect
public class AspectObject {
//与xml的value值是一致的
@Pointcut(value="execution(* Spring.DangDang.bookBooks(Integer)) && args(userId)")
public void publicPointcut1(Integer userId){}
@Pointcut(value="execution(* Spring.DangDang.* (..))")
public void publicPointcut(){}
@Before(value="publicPointcut1(userId)")
public void beginRun(Integer userId){
if(userId != null){
System.out.println("客户已登录,userId号为:"+userId);
}else{
System.out.println("客户未登陆,已让客户去登录");
userId = 12;
System.out.println("客户登录成功,userId号为:"+userId);
}
}
@After(value="publicPointcut1(userId)")
public Integer endRun(Integer userId){
Integer orderId = 120;
System.out.println("已生成订单,订单号为:"+orderId);
return orderId;
}
@Around(value="execution(* Spring.DangDang.sendBook(Integer,Integer)) && args(userId,orderId)")
public Object round(ProceedingJoinPoint point,Integer userId,Integer orderId){
System.out.println("前,userId:"+userId+",orderId:"+orderId);
Object returnObject = null;
try {
returnObject = point.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("后,userId:"+userId+",orderId:"+orderId);
return returnObject;
}
//返回通知,是获取方法返回值
@AfterReturning(value="execution(* Spring.DangDang.isGetBook (..))",returning="isGet")
public void afterRun(boolean isGet){
System.out.println("返回值通知------------");
if(isGet){
System.out.println("客户已收到");
}else{
System.out.println("客户未收到");
}
}
//异常通知,是获取方法中出现错误的异常
@AfterThrowing(value="publicPointcut() and bean(dangdang1)",throwing="t")
public void afterThrowing(Throwable t){
System.out.println("异常通知------------");
System.out.println("aopThrowMethod t="+t.getMessage());
}
}
使用注解的方法,AopTest类:
@EnableAspectJAutoProxy
@ComponentScan(basePackages="Spring")
public class AopTest {
public static void main(String[] args) {
String resource = "Spring";
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopTest.class);
DangDang dangdang = (DangDang) context.getBean("dangdang1");
dangdang.bookBooks(null);
System.out.println();
dangdang.sendBook(null,null);
System.out.println();
dangdang.isGetBook();
}
}
运行AopTest类,运行效果如下:
客户未登陆,已让客户去登录
客户登录成功,userId号为:12
当当网-书籍部门,客户订书了
已生成订单,订单号为:120
前,userId:null,orderId:null
当当网-书籍部门,将书送到指定地址的客户手中
后,userId:null,orderId:null
客户是否收到书籍
返回值通知------------
客户未收到
使用半注解半xml的形式:
使用上述注解方式的AsceptObject与DangDang类
使用上述xml方式的AopTest类
改变aop-applicationConfig.xml文件:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 使用全包搜索 --> <context:component-scan base-package="Spring"></context:component-scan> <!-- 使用aop:aspectj-autoproxy标签根据类中的注解来自动完成切点 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
运行AopTest类,运行效果如下:
客户已登录,userId号为:1
当当网-书籍部门,客户订书了
已生成订单,订单号为:120
前,userId:1,orderId:120
当当网-书籍部门,将书送到指定地址的客户手中
后,userId:1,orderId:120
客户是否收到书籍
返回值通知------------
客户未收到