AOP中关键性概念 :
①、连接点(Joinpoint):程序执行过程中明确的点,如方法的调用,或者异常的抛出,
②、目标(Target):被通知(被代理)的对象 ?注1:完成具体的业务逻辑
③、通知(Advice):在某个特定的连接点上执行的动作,同时Advice也是程序代码的具体实现,例 ? ? ? ? 如一个实现日志记录的代码(通知有些书上也称为处理) ?注2:完成切面编程
④、代理(Proxy):将通知应用到目标对象后创建的对象(代理=目标+通知), ? ? ? ?例子:外科医生+护士 注3:只有代理对象才有AOP功能,而AOP的代码是写在通知的方法里面的
⑤、切入点(Pointcut):多个连接点的集合,定义了通知应该应用到那些连接点。 ? ? ? (也将Pointcut理解成一个条件 ,此条件决定了容器在什么情况下将通知和目标组合成代理返 ? ? ? ? ?回给外部程序)
⑥、适配器(Advisor):适配器=通知(Advice)+切入点(Pointcut)
?AOP的核心点(通知)
1,前置通知
异常类
package com.hmf.exception;
public class PriceException extends RuntimeException {
?? ?public PriceException() { ?? ??? ?super(); ?? ?}
?? ?public PriceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { ?? ??? ?super(message, cause, enableSuppression, writableStackTrace); ?? ?}
?? ?public PriceException(String message, Throwable cause) { ?? ??? ?super(message, cause); ?? ?}
?? ?public PriceException(String message) { ?? ??? ?super(message); ?? ?}
?? ?public PriceException(Throwable cause) { ?? ??? ?super(cause); ?? ?} ?? ? }
接口IBookBiz有两个方法
package com.hmf.biz;
public interface IBookBiz { ?? ?// 购书 ?? ?public boolean buy(String userName, String bookName, Double price);
?? ?// 发表评论 ?? ?public void comment(String userName, String comments); }
实现类BookBizImpl?继承接口 并重写方法
package com.hmf.biz;
import com.hmf.exception.PriceException;
public class BookBizImpl implements IBookBiz {
?? ?public BookBizImpl() { ?? ??? ?super(); ?? ?}
?? ?public boolean buy(String userName, String bookName, Double price) { ?? ??? ?if (null == price || price <= 0) { ?? ??? ??? ?//?通过控制台的输出方式模拟购书 ?? ??? ??? ?throw new PriceException("book price exception"); ?? ??? ?} ?? ??? ?System.out.println(userName + " buy " + bookName + ", spend " + price); ?? ??? ?return true; ?? ?}
?? ?public void comment(String userName, String comments) { ?? ??? ?//?通过控制台的输出方式模拟发表评论 ?? ??? ?System.out.println(userName + " say:" + comments); ?? ?}
}
前置通知MyMethodBeforeAdvice 实现一个接口 类代码?
package com.hmf.advice;
import java.lang.reflect.Method; import java.util.Arrays;
import org.springframework.aop.MethodBeforeAdvice;
public class MyMethodBeforeAdvice implements MethodBeforeAdvice { ?? ?/** ?? ? * target:目标对象 ?? ? * method:被触发目标对象的方法 ?? ? * args:目标对象的目标方法携带的参数 ?? ? */ ?? ? ?? ?public void before(Method method, Object[] args, Object target) throws Throwable { ?? ??? ?String targetName = target.getClass().getName(); ?? ??? ?String methodName = method.getName(); ?? ??? ?String params = Arrays.toString(args); ?? ??? ?String msg = "买书评论前加系统日志:"+targetName+"."+methodName+",前置通知携带的参数:"+params; ?? ??? ?System.out.println(msg);
?? ?}
}
配置
<!-- aop 目标--> <bean name="bookBiz" class="com.hmf.biz.BookBizImpl"></bean> <!-- 前置通知 --> <bean name="myBefore" class="com.hmf.advice.MyMethodBeforeAdvice"></bean>
<!-- 生成代理(目标对象+通知) --> ?? ?<bean class="org.springframework.aop.framework.ProxyFactoryBean" ?? ??? ?id="proxyFactoryBean"> ?? ??? ?<property name="target" ref="bookBiz"></property> ?? ??? ?<!-- 代理工厂生产的代理需要实现的接口列表 --> ?? ??? ?<property name="proxyInterfaces"> ?? ??? ??? ?<list> ?? ??? ??? ??? ?<value>com.hmf.biz.IBookBiz</value> ?? ??? ??? ?</list> ?? ??? ?</property> ?? ??? ?<property name="interceptorNames"> ?? ??? ??? ?<list> ?? ??? ??? ??? ?<value>myBefore</value> ?? ??? ??? ?</list> ?? ??? ?</property> ?? ?</bean> ?
常规业务代码(测试
package com.hmf.test;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.hmf.biz.IBookBiz;
public class AopTest { ?? ?public static void main(String[] args) { ?? ??? ?ApplicationContext applicationContext=new ClassPathXmlApplicationContext("/spring-context.xml"); ?? ??? ?IBookBiz bookBiz =(IBookBiz) applicationContext.getBean("proxyFactoryBean"); ?? ??? ?bookBiz.buy("小小与大鱼", "bb",1.1 ); ?? ??? ?bookBiz.comment("你怎么有点可爱", "hhhh"); ?? ?} } ?? ?
三个参数?
?????* target:目标对象 ?? ? * method:被触发目标对象的方法 ?? ? * args:目标对象的目标方法携带的参数
结果?
2,后置通知?
后置通知代码类(MyAfterRetruningAdvice?)
package com.hmf.advice;
import java.lang.reflect.Method; import java.util.Arrays;
import org.springframework.aop.MethodBeforeAdvice;
public class MyMethodBeforeAdvice implements MethodBeforeAdvice { ?? ?/** ?? ? * target:目标对象 ?? ? * method:被触发目标对象的方法 ?? ? * args:目标对象的目标方法携带的参数 ?? ? */ ?? ? ?? ?public void before(Method method, Object[] args, Object target) throws Throwable { ?? ??? ?String targetName = target.getClass().getName(); ?? ??? ?String methodName = method.getName(); ?? ??? ?String params = Arrays.toString(args); ?? ??? ?String msg = "买书评论前加系统日志:"+targetName+"."+methodName+",前置通知携带的参数:"+params; ?? ??? ?System.out.println(msg);
?? ?}
}
配置
?<!-- 后置通知 --> <bean name="myAfter" class="com.hmf.advice.MyAfterReturningAdvice"></bean>
先运行前置再运行后置通知(结果
?3,环绕通知
环绕通知代码(MyMethodInterceptor?)
package com.hmf.advice;
import java.lang.reflect.Method; import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation;
/** ?* 环绕通知 ?* @author Administrator ?* ?*/ public class MyMethodInterceptor implements MethodInterceptor {
?? ?public Object invoke(MethodInvocation invocation) throws Throwable { ?? ??? ?Object target = invocation.getThis(); ?? ??? ?Method method = invocation.getMethod(); ?? ??? ?Object[] args = invocation.getArguments(); ?? ??? ?// a.jsp window.open(b.jsp) ?? ??? ?// b.jsp xxx->返回object->b.jsp window.close();window.getArguments; ?? ??? ?String targetName = target.getClass().getName(); ?? ??? ?String methodName = method.getName(); ?? ??? ?String params = Arrays.toString(args); ?? ??? ?String msg = "【环绕通知】:正在调用->" + targetName + "." + methodName + ",携带的参数:" + params; ?? ??? ?System.out.println(msg); ?? ??? ?Object returnValue = invocation.proceed(); ?? ??? ?String msg2 = "【环绕通知】:目标对象所调用的方法的返回值:" + returnValue; ?? ??? ?System.out.println(msg2); ?? ??? ?return returnValue; ?? ?}
}
配置
<!-- 环绕通知 --> <bean name="MyMethod" class="com.hmf.advice.MyMethodInterceptor"></bean> ?? ?<!-- 生成代理(目标对象+通知) --> ?? ?<bean class="org.springframework.aop.framework.ProxyFactoryBean" ?? ??? ?id="proxyFactoryBean"> ?? ??? ?<property name="target" ref="bookBiz"></property> ?? ??? ?<!-- 代理工厂生产的代理需要实现的接口列表 --> ?? ??? ?<property name="proxyInterfaces"> ?? ??? ??? ?<list> ?? ??? ??? ??? ?<value>com.hmf.biz.IBookBiz</value> ?? ??? ??? ?</list> ?? ??? ?</property> ?? ??? ?<property name="interceptorNames"> ?? ??? ??? ?<list> ?? ??? ??? ??? ?<value>myBefore</value> ?? ??? ??? ??? ?<value>myAfter</value> ?? ??? ??? ??? ?<value>MyMethod</value> ?? ??? ??? ?</list> ?? ??? ?</property> ?? ?</bean>
结果
4,异常通知
?package com.hmf.advice;
import org.springframework.aop.ThrowsAdvice;
import com.hmf.exception.PriceException;
/** ?* 异常通知 ?* @author Administrator ?* ?*/ public class MyThrowsAdvice implements ThrowsAdvice { ?? ?public void afterThrowing( PriceException ex ) { ?? ??? ?System.out.println("价格输入有误,购买失败,请重新输入!!!"); ?? ?} }
配置
<!-- 异常通知 --> <bean name="MyThrows" class="com.hmf.advice.MyThrowsAdvice"></bean> ?? ?<!-- 生成代理(目标对象+通知) --> ?? ?<bean class="org.springframework.aop.framework.ProxyFactoryBean" ?? ??? ?id="proxyFactoryBean"> ?? ??? ?<property name="target" ref="bookBiz"></property> ?? ??? ?<!-- 代理工厂生产的代理需要实现的接口列表 --> ?? ??? ?<property name="proxyInterfaces"> ?? ??? ??? ?<list> ?? ??? ??? ??? ?<value>com.hmf.biz.IBookBiz</value> ?? ??? ??? ?</list> ?? ??? ?</property> ?? ??? ?<property name="interceptorNames"> ?? ??? ??? ?<list> ?? ??? ??? ??? ?<value>myBefore</value> ?? ??? ??? ??? ?<value>myAfter</value> ?? ??? ??? ??? ?<value>MyMethod</value> ?? ??? ??? ??? ?<value>MyThrows</value> ?? ??? ??? ?</list> ?? ??? ?</property> ?? ?</bean>
结果(当价格改为负数时,报错执行异常通知的代码
5,过滤通知
没有代码,只需要配置? ?给buy方法的后置通知添加过滤通知
只要买书有后置通知,评论的没有
|