The*_*use 4 java spring spring-aop
我正在使用带有Spring AOP的slf4j进行日志记录和异常目的.在某些类中有一些方法形成了一个方法链接.我能够记录第一个方法的入口和出口点,但是当这个方法调用另一个方法时,AOP只记录第一个方法的入口和出口点.我想记录每个方法的入口和退出点,@Around这里使用注释是Pseudo代码来解释我想要的是
package com.sample;
public class Test implements T{
@Override
public void show() {
System.out.println("Test.show()");
test();
}
void Test(){
//Want to log entry and exit point of this method whenever this method called by any other method
//The method may belongs to same class or different package's different class
}
Run Code Online (Sandbox Code Playgroud)
spring.xml 是这样的
<bean id="exceptionAspect" class="com.sample.ExceptionAspect"/>
<bean id="test" class="com.sample.Test"/>
Run Code Online (Sandbox Code Playgroud)
我的Advise class样子
@Aspect
public class LoggingAspect {
@Around(value="execution (* com.sample.*.*(..))||"+
"execution(* some other package.*.*(..))")
public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
logger.info("Execution of : " + joinPoint.getSignature() + " Started");
joinPoint.proceed();
logger.info("Execution of : " + joinPoint.getSignature() + " completed");
}
}
Run Code Online (Sandbox Code Playgroud)
客户类
package com.test;
public class App {
public static void main(String[] args) throws Exception {
ApplicationContext appContext = new ClassPathXmlApplicationContext(
"classpath:/META-INF/spring.xml");
T test=(T) appContext.getBean("test");
test.show();
}
Run Code Online (Sandbox Code Playgroud)
任何帮助是极大的赞赏..
A4L*_*A4L 11
你想要做的事情是不可能的Spring AOP(至少没有重构建议的方法).原因是Spring AOP是proxy based,这意味着它为每个bean创建一个代理类并注入它而不是你的实现.代理具有bean的所有方法,并添加了方面功能.因此,当您调用bean的方法(实际上是bean的代理)时,将执行方面代码,然后通过委托调用您的方法.因此,当您的方法调用其他方法时,调用是使用真实bean执行的,而不是那些代理 - 如果存在的话 - 那么您就不会得到您期望的输出.
您可以想到它看起来像某样的代理:
class MyBeanProxy implements MyBean {
MyBeanImpl theBean;
public void foo() {
// aspect code
theBean.foo();
}
public void bar() {
// aspect code
theBean.bar();
}
}
Run Code Online (Sandbox Code Playgroud)
你的豆子是什么样的
interface MyBean {
foo();
bar();
}
@Component("my_bean")
class MyBeanImpl implements MyBean {
public void foo() {
System.out.println("foo");
bar();
}
public void bar() {
System.out.println("bar");
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,当您foo()通过代理进行调用时,会执行方面代码,并且将调用委托MyBeanImpl#foo(),bar()调用位置.现在很明显,bar()不会执行方面代码.
现在你怎么能让它发挥作用?
1 -以这样的方式重构代码:对于要为其执行方面代码的方法,调用发生在代理对象上,而不是在bean本身上.为此,您可以获取实际代理并使用它来调用您的方法.
public void foo() {
System.out.println("foo");
MyBean myBeanProxy = (MyBean) AopContext.currentProxy();
myBeanProxy.bar();
}
Run Code Online (Sandbox Code Playgroud)
请注意,这种方法更像是一种破解,而不是干净的方式来完成这项工作.例如,显然myBeanProxy没有当前对象状态的线索.
2 -重构你bar()在另一个bean中编码的代码,你可以使用你的代码来检索appContext.
3-使用AspectJ:将Aspect代码注入目标类本身(真实的东西!)
这是使用AspectJ的小例子
方面
package com.aj;
import java.util.Arrays;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class MyAspect {
@Around("execution( * com.app.services.*.* (..) )")
public Object callDurationAdvice(ProceedingJoinPoint pjp) throws Throwable {
Signature signature = pjp.getSignature();
Object[] args = pjp.getArgs();
String argList = Arrays.toString(args);
System.out.println(signature.getDeclaringTypeName() +
"." + signature.getName() + "(" + argList + ") started");
long s = System.nanoTime();
Object proceed = pjp.proceed(args);
long e = System.nanoTime();
System.out.println(signature.getDeclaringTypeName() +
"." + signature.getName() + "(" + argList + ") ended after " +
((double)(e-s)/1000000) + " ms");
return proceed;
}
}
Run Code Online (Sandbox Code Playgroud)
某些包装中的一类女巫应该成为该方面的目标
package com.app.services;
public class ServicesVersionInfo {
public static String getVersion() {
return getVersionNumber() + " " + getVersionStage();
}
public static String getVersionNumber() {
return "1.0.0";
}
public static String getVersionStage() {
return "ALPHA";
}
}
Run Code Online (Sandbox Code Playgroud)
该应用程序
package com.app;
import com.app.services.ServicesVersionInfo;
public class App {
public static void main(String[] args) {
System.out.println("App services version: " +
ServicesVersionInfo.getVersion());
}
}
Run Code Online (Sandbox Code Playgroud)
冉,这应该输出一些谎言
com.app.services.ServicesVersionInfo.getVersion([]) started
com.app.services.ServicesVersionInfo.getVersionNumber([]) started
com.app.services.ServicesVersionInfo.getVersionNumber([]) ended after 0.004862 ms
com.app.services.ServicesVersionInfo.getVersionStage([]) started
com.app.services.ServicesVersionInfo.getVersionStage([]) ended after 0.005673 ms
com.app.services.ServicesVersionInfo.getVersion([]) ended after 0.378877 ms
App services version: 1.0.0 ALPHA
Run Code Online (Sandbox Code Playgroud)
最后,这里有一些类似的问题和进一步的阅读:
| 归档时间: |
|
| 查看次数: |
6825 次 |
| 最近记录: |