我有多个接口,每个接口定义了多种方法,如下所示:
public interface X {
void methodX1;
void methodX2(String s);
}
public interface Y {
void methodY1;
void methodY2(int i);
void methodY3(SomeType s);
}
....
当前方法实现如下:
public class XImpl implements X {
public void methodX1() {
// method implementation
}
}
对于接口的每个实现,我都需要用try-with-resource
块包装方法实现,如下所示:
public class XImpl implements X {
public void methodX1() {
try (SomeResource res = new SomeResource()) {
// method implementation
}
}
}
由于我对AOP的局限性,我相信在这种情况下,我们可以在JoinPoint
即方法之前和之后进行操作,但是如何包装上述实现?我正在寻找是否可以通过使用批注或lambda来完成,即不需要单独更改每种方法的事情。
任何关于如何实现此目标的想法将不胜感激。
答案 0 :(得分:2)
由于我对AOP的局限性,我相信在这种情况下,我们可以在JoinPoint即方法之前和之后做事,但是如何包装上述实现?
您读过非常好的Spring AOP manual吗?您会注意到的第一件事就是对建议类型的解释,不仅在建议前后,而且还有围绕建议。这就是您要使用的。
基本上是它的工作方式:
Java帮助程序类:
package de.scrum_master.app;
public class SomeType {}
package de.scrum_master.app;
public class SomeResource implements AutoCloseable {
@Override public void close() throws Exception {}
}
接口:
package de.scrum_master.app;
public interface X {
void methodX1();
int methodX2(String s);
}
package de.scrum_master.app;
public interface Y {
void methodY1();
String methodY2(int i);
void methodY3(SomeType s);
}
接口实现+驱动程序应用程序
:我在AspectJ中实现了示例,而不是在Spring AOP中实现了。因此,您看不到任何应用程序上下文,但是您知道该怎么做,不是吗?
package de.scrum_master.app;
import org.springframework.stereotype.Component;
@Component
public class MyImpl implements X, Y {
@Override public void methodY1() { System.out.println("Y1"); methodX2("bar"); }
@Override public String methodY2(int i) { System.out.println("Y2"); return "dummy"; }
@Override public void methodY3(SomeType s) { System.out.println("Y3"); }
@Override public void methodX1() { System.out.println("X1"); methodY1(); }
@Override public int methodX2(String s) { System.out.println("X2"); return 42; }
public static void main(String[] args) {
MyImpl myImpl = new MyImpl();
myImpl.methodX1();
myImpl.methodX2("foo");
myImpl.methodY1();
myImpl.methodY2(11);
myImpl.methodY3(new SomeType());
}
}
请注意,methodX1()
和methodY1()
都在内部调用方法。对于以后的Spring AOP和AspectJ之间的区别,这将是重要的。
方面:
在Spring AOP中,您可以省略execution(* *(..)) &&
部分,我只是在这里使用它,以避免诸如call()
之类的其他联接点被截取并且日志变得肿。由于Spring AOP除了execution()
以外,对其他内容一无所知,因此这里没有必要。切入点的... || ...
块周围的括号也可以消失。
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import de.scrum_master.app.SomeResource;
@Component
@Aspect
public class WrapMethodsAspect {
@Around("execution(* *(..)) && (within(de.scrum_master.app.X+) || within(de.scrum_master.app.Y+))")
public Object wrapperAdvice(ProceedingJoinPoint thisJoinPoint) throws Throwable {
System.out.println("Wrapping " + thisJoinPoint);
try (SomeResource res = new SomeResource()) {
return thisJoinPoint.proceed();
}
finally {
System.out.println("Unwrapping " + thisJoinPoint);
}
}
}
使用AspectJ控制台输出:
Wrapping execution(void de.scrum_master.app.MyImpl.main(String[]))
Wrapping execution(void de.scrum_master.app.MyImpl.methodX1())
X1
Wrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Y1
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Unwrapping execution(void de.scrum_master.app.MyImpl.methodX1())
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Y1
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Wrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Y2
Unwrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
Y3
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
Unwrapping execution(void de.scrum_master.app.MyImpl.main(String[]))
您在这里注意到两件事:
main(..)
方法的执行。 Spring AOP不会发生这种情况。使用Spring AOP进行控制台输出:
Wrapping execution(void de.scrum_master.app.MyImpl.methodX1())
X1
Unwrapping execution(void de.scrum_master.app.MyImpl.methodX1())
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Y1
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Wrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Y2
Unwrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
Y3
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
在大多数情况下,Spring AOP对于Spring用户而言已足够。但是,如果您需要一种更强大的方法来捕获其他类型的切入点,例如内部的嵌套方法调用,则可以使用AspectJ via load-time weaving (LTW)。
答案 1 :(得分:0)
也许是这样的:
public abstract class ResourceProcessingService {
protected <T> T processResource(Resource resource, Function<Reader, T> function) {
try (InputStream fileInputStream = resource.getInputStream()) {
Reader reader = new BufferedReader(new InputStreamReader(fileInputStream, StandardCharsets.UTF_8));
return function.apply(reader);
} catch (IOException e) {
throw new YourRuntimeException("Could not process resource: " + resource.getFilename() + ", " + e.getMessage());
}
}
}
在您的具体实现中,您现在可以执行以下操作:
public class XImpl extends ResourceProcessingService implements X {
public double performSomeResourceProcessing() {
return processResource(yourResource, (reader) -> readTheResource(reader));
}
private double readTheResource(Reader reader) {
// perform the resource reading
}
}