内容简介:山有木兮木有枝,心悦君兮君不知。到目前位置,关于
山有木兮木有枝,心悦君兮君不知。
概述
到目前位置,关于 aop 的部分,我们已经完成了以下功能
- 根据
Bean的名称和方法名,获取Method对象。MethodLocatingFactory - 给定一个类的方法,判断该方法是否符合
Pointcut的表达式。AspectJExpressionPointcut - 实现了前置,后置和异常的通知。
AspectJBeforeAdvice,AspectJAfterReturningAdvice,AspectJAfterThrowingAdvice - 实现了
Advice按次续依次执行。ReflectiveMethodInvocation - 给定一个
AopConif,使用Cglib生成一个对象的代理。
接下来只剩下最后一个工作,读取 bean-v5.xml 创建 BeanDefinition 。
分析aop:config标签
在创建 BeanDefinition 之前我们先看一下 aop:config 的定义,之前 Bean 的定义。
<bean id = "nioCoder"
class = "com.niocoder.service.v1.NioCoderService">
</bean>
现在 Bean 的定义
<!-- aop 配置-->
<aop:config>
<!-- aop 核心配置 依赖tx-->
<aop:aspect ref="tx">
<!-- 切入点配置 包下面的placeOrder 方法-->
<aop:pointcut id="placeOrder"
expression="execution(* com.niocoder.service.v5.*.placeOrder(..))"/>
<!-- 通知配置,-->
<aop:before pointcut-ref="placeOrder" method="start"/>
<aop:after-returning pointcut-ref="placeOrder" method="commit"/>
<aop:after-throwing pointcut-ref="placeOrder" method="rollback"/>
</aop:aspect>
</aop:config>
之前如果 Bean 有其它额外的属性,我们都是通过 PropertyValue 或 ConstructorArgument 来表示。但 aop:config 的标签该如何表达呢?
spring 还是通过 GenericBeanDefinition 来表示 aop:config 标签,关于标签属性的映射,参考下图
<aop:pointcut id="placeOrder"
expression="execution(* com.niocoder.service.v5.*.placeOrder(..))"/>
<aop:before pointcut-ref="placeOrder" method="start"/>
通过上图的构造器类型,我们发现这与我们之前创建 AspectJBeforeAdvice 的构造器参数不匹配。
public AspectJBeforeAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, Object adviceObject) {
super(adviceMethod, pointcut, adviceObject);
}
因上图的第一个构造器参数中含有 methodName ,所以我们只需将修改 adviceObject 修改为 AspectInstanceFactory 。关于 AspectInstanceFactory 的类图设计如下:
FactoryBean
工厂bean,
/**
* 工厂bean
* @author zhenglongfei
*/
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
}
BeanFactoryAware
有些实现类需要用到 BeanFactory ,实现该接口即可。
public interface BeanFactoryAware {
/**
* set beanFactory
*
* @param beanFactory
* @throws BeansException
*/
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
AspectInstanceFactory
/**
* @author zhenglongfei
*/
public class AspectInstanceFactory implements BeanFactoryAware {
private String aspectBeanName;
private BeanFactory beanFactory;
public void setAspectBeanName(String aspectBeanName) {
this.aspectBeanName = aspectBeanName;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
if (!StringUtils.hasText(this.aspectBeanName)) {
throw new IllegalArgumentException(" 'aspectBeanName' is required");
}
}
public Object getAspectInstance() throws Exception {
return this.beanFactory.getBean(this.aspectBeanName);
}
}
MethodLocatingFactory
实现 FactoryBean<Method> 和 BeanFactoryAware
public class MethodLocatingFactory implements FactoryBean<Method>, BeanFactoryAware {
}
AbstractAspectJAdvice
将 Object adviceObject 替换成 AspectInstanceFactory adviceObjectFactory ,修改 invokeAdviceMethod() 方法,对象是从 benFactory 中根据 aspectBeanName 获取。
ublic abstract class AbstractAspectJAdvice implements Advice {
private Method adviceMethod;
private AspectJExpressionPointcut pointcut;
private Object adviceObject;
public AbstractAspectJAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, Object adviceObject) {
this.adviceMethod = adviceMethod;
this.pointcut = pointcut;
this.adviceObject = adviceObject;
}
@Override
public Pointcut getPointcut() {
return pointcut;
}
public Method getAdviceMethod() {
return this.adviceMethod;
}
public void invokeAdviceMethod() throws Throwable {
adviceMethod.invoke(adviceObject);
}
}
AspectJBeforeAdvice
因抽象方法修改,子类构造函数也需要修改, AspectJAfterReturningAdvice 和 AspectJAfterThrowingAdvice 也需要修改
ublic class AspectJBeforeAdvice extends AbstractAspectJAdvice {
public AspectJBeforeAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, Object adviceObject) {
super(adviceMethod, pointcut, adviceObject);
}
......
}
AbstractV5Test
提出公工方法到一个测试类中
public class AbstractV5Test {
protected BeanFactory getBeanFactory(String configFile) {
DefaultBeanFactory defaultBeanFactory = new DefaultBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(defaultBeanFactory);
reader.loadBeanDefinition(new ClassPathResource(configFile));
return defaultBeanFactory;
}
protected Method getAdviceMethod(String methodName) throws Exception {
return TransactionManager.class.getMethod(methodName);
}
protected AspectInstanceFactory getAspectInstanceFactory(String targetBeanName) {
AspectInstanceFactory factory = new AspectInstanceFactory();
factory.setAspectBeanName(targetBeanName);
return factory;
}
}
CglibAopProxyTest
动态获取 AspectInstanceFactory
public class CglibAopProxyTest extends AbstractV5Test {
private static AspectJBeforeAdvice beforeAdvice = null;
private static AspectJAfterReturningAdvice afterAdvice = null;
private AspectJExpressionPointcut pc = null;
private BeanFactory beanFactory = null;
private NioCoderService nioCoderService = null;
private AspectInstanceFactory aspectInstanceFactory = null;
@Before
public void setUp() throws Exception {
MessageTracker.clearMsgs();
String expression = "execution(* com.niocoder.service.v5.*.placeOrder(..))";
pc = new AspectJExpressionPointcut();
pc.setExpression(expression);
nioCoderService = new NioCoderService();
beanFactory = this.getBeanFactory("bean-v5.xml");
aspectInstanceFactory = this.getAspectInstanceFactory("tx");
aspectInstanceFactory.setBeanFactory(beanFactory);
beforeAdvice = new AspectJBeforeAdvice(
getAdviceMethod("start"),
pc,
aspectInstanceFactory);
afterAdvice = new AspectJAfterReturningAdvice(
getAdviceMethod("commit"),
pc,
aspectInstanceFactory);
}
@Test
public void testGetProxy() {
AopConfig config = new AopConfigSupport();
config.addAdvice(beforeAdvice);
config.addAdvice(afterAdvice);
config.setTargetObject(nioCoderService);
CglibProxyFactory proxyFactory = new CglibProxyFactory(config);
NioCoderService proxy = (NioCoderService) proxyFactory.getProxy();
proxy.placeOrder();
List<String> msgs = MessageTracker.getMsgs();
Assert.assertEquals(3, msgs.size());
Assert.assertEquals("start tx", msgs.get(0));
Assert.assertEquals("place order", msgs.get(1));
Assert.assertEquals("commit tx", msgs.get(2));
}
}
ReflectiveMethodInvocationTest
动态获取 AspectInstanceFactory
public class ReflectiveMethodInvocationTest extends AbstractV5Test{
private AspectJBeforeAdvice beforeAdvice = null;
private AspectJAfterReturningAdvice afterReturningAdvice;
private AspectJAfterThrowingAdvice afterThrowingAdvice;
private NioCoderService nioCoderService;
private AspectJExpressionPointcut pc = null;
private BeanFactory beanFactory = null;
private AspectInstanceFactory aspectInstanceFactory = null;
@Before
public void setUp() throws Exception {
nioCoderService = new NioCoderService();
String expression = "execution(* com.niocoder.service.v5.*.placeOrder(..))";
pc = new AspectJExpressionPointcut();
pc.setExpression(expression);
beanFactory = this.getBeanFactory("bean-v5.xml");
aspectInstanceFactory = this.getAspectInstanceFactory("tx");
aspectInstanceFactory.setBeanFactory(beanFactory);
MessageTracker.clearMsgs();
beforeAdvice = new AspectJBeforeAdvice(TransactionManager.class.getMethod("start"), pc, aspectInstanceFactory);
afterReturningAdvice = new AspectJAfterReturningAdvice(TransactionManager.class.getMethod("commit"), pc, aspectInstanceFactory);
afterThrowingAdvice = new AspectJAfterThrowingAdvice(TransactionManager.class.getMethod("rollback"), pc, aspectInstanceFactory);
}
@Test
public void textMethodInvocation() throws Throwable {
Method targetMethod = NioCoderService.class.getMethod("placeOrder");
List<MethodInterceptor> interceptorList = new ArrayList<>();
interceptorList.add(beforeAdvice);
interceptorList.add(afterReturningAdvice);
ReflectiveMethodInvocation mi = new ReflectiveMethodInvocation(nioCoderService, targetMethod, new Object[0], interceptorList);
mi.proceed();
List<String> msgs = MessageTracker.getMsgs();
Assert.assertEquals(3, msgs.size());
Assert.assertEquals("start tx", msgs.get(0));
Assert.assertEquals("place order", msgs.get(1));
Assert.assertEquals("commit tx", msgs.get(2));
}
@Test
public void testAfterThrowing() throws Throwable{
Method targetMethod = NioCoderService.class.getMethod("placeOrderWithException");
List<MethodInterceptor> interceptorList = new ArrayList<>();
interceptorList.add(beforeAdvice);
interceptorList.add(afterThrowingAdvice);
ReflectiveMethodInvocation mi = new ReflectiveMethodInvocation(nioCoderService, targetMethod, new Object[0], interceptorList);
try {
mi.proceed();
} catch (Throwable t) {
List<String> msgs = MessageTracker.getMsgs();
Assert.assertEquals(2, msgs.size());
Assert.assertEquals("start tx", msgs.get(0));
Assert.assertEquals("rollback tx", msgs.get(1));
return;
}
Assert.fail("No Exception thrown");
}
}
代码下载
解析aop:config标签
TODO ….
代码下载
参考资料
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
结网@改变世界的互联网产品经理
王坚 / 人民邮电出版社 / 2013-5-1 / 69.00元
《结网@改变世界的互联网产品经理(修订版)》以创建、发布、推广互联网产品为主线,描述了互联网产品经理的工作内容,以及应对每一部分工作所需的方法和工具。产品经理的工作是围绕用户及具体任务展开的,《结网@改变世界的互联网产品经理(修订版)》给出的丰富案例以及透彻的分析道出了从发现用户到最终满足用户这一过程背后的玄机。新版修改了之前版本中不成熟的地方,强化了章节之间的衔接,解决了前两版中部分章节过于孤立......一起来看看 《结网@改变世界的互联网产品经理》 这本书的介绍吧!