我是 AOP 的新手,我试图理解方法拦截器和 MethodAdvice(即 MethodBeforeAdvice 或 MethodAfterAdvice)之间的区别。在我看来,两者都在做同样的事情,即在方法调用时调用。我们什么时候应该使用 MethodInterceptor 和 MethodAdvice。
我正在研究 mysql 主从复制。我正在使用 spring data jpa(spring boot)。
我需要的是所有写入操作都转到主服务器,而只读操作则均匀分布在多个只读从服务器之间。
为此我需要:
使用特殊的 JDBC 驱动程序:com.mysql.jdbc.ReplicationDriver
在 URL 中设置复制:
spring:
datasource:
driverClassName: com.mysql.jdbc.ReplicationDriver
url: jdbc:mysql:replication://127.0.0.1:3306,127.0.0.1:3307/MyForum?user=root&password=password&autoReconnect=true
test-on-borrow: true
validation-query: SELECT 1
database: MYSQL
Run Code Online (Sandbox Code Playgroud)
需要关闭自动提交。(*) 连接需要设置为只读。
为了确保 JDBC Connection 设置为只读,我创建了一个注释和一个简单的 AOP 拦截器。
注解
package com.xyz.forum.replication;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by Bhupati Patel on 02/11/15.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ReadOnlyConnection {
}
Run Code Online (Sandbox Code Playgroud)
拦截器
package com.xyz.forum.replication;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.hibernate.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; …Run Code Online (Sandbox Code Playgroud)
我对 Spring AOP 有疑问。我想在切入点中获取 Student 对象。但我的 JoinPoints 可以以任何优先级拥有该对象。
查看下面的代码片段,了解我创建的两个不同的连接点和切入点:
public Student createStudent(String s, Student student) {...}
public Student updateStudent(Student student, String s) {...}
@Before("args(..,com.hadi.student.Student)")
public void myAdvice(JoinPoint jp) {
Student student = null;
for (Object o : jp.getArgs()) {
if (o instanceof Student) {
student = (Student) o;
}
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码仅适用于第一个 JoinPoint。所以问题是如何创建一个切入点,该切点将在输入参数中针对 Student 的任何情况执行。
我无法使用下面的代码,它抛出runtimeException:
@Before("args(..,com.hadi.student.Student,..)")
我让代码变得容易理解,实际上我的切入点比这个大得多。所以请用args方式回答。
假设我想找到所有用@Controller 注释的类,我会创建这个切入点:
@Pointcut("within(@org.springframework.stereotype.Controller *)")
public void controllerPointcut() {}
Run Code Online (Sandbox Code Playgroud)
但是找不到那些用@RestController 注释的控制器。因为 RestController 本身是用@Controller 注释的。
关于如何查找使用 @Controller 或 @RestController 注释的类而无需创建两个 Pointcuts 的任何想法?
======编辑====我在这里的真正意图如下:
父注释:
public @interface ParentAnnotation {}
Run Code Online (Sandbox Code Playgroud)
子注释(用@ParentAnnotation 注释):
@ParentAnnotation
public @interface ChildAnnotation {}
Run Code Online (Sandbox Code Playgroud)
A类:
@ParentAnnotation
public class MyClassA {}
Run Code Online (Sandbox Code Playgroud)
B类:
@ChildAnnotation
public class MyClassB {}
Run Code Online (Sandbox Code Playgroud)
现在我想通过@ParentAnnotation 找到MyClassA 和MyClassB。找到MyClassA是没有问题的,但是MyClassB是用@ParentAnnotation间接注释的,有没有通用的方法来处理这种情况?
我想在我的方面之前和之后获取请求/响应正文和标头(如果可用)或如何获取它们。
我的意思是我认为前面的注释应该适用于请求,
注释后应适用于响应。可 ?
到目前为止我已经尝试过:
我尝试了日志库,这对我来说非常复杂,我不知道如何使用它。所以我放弃了。
执行器可以做一些技巧,但我正在做额外的工作,比如端点调用多少次等,因此我不能使用执行器。
另外,我尝试获取至少如下所示的请求标头,但我认为该标头始终相同。我无法像 httpservetrequest 那样获得 httpservletresponse 。
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
Run Code Online (Sandbox Code Playgroud)
那么
request.getHeader("date")requestbody 呢?
如何获取请求体?响应主体?响应头?
我的方面文件:
@Aspect
@Component
public class AppAspect implements ResponseInfo{
@Before("execution(@(@org.springframework.web.bind.annotation.RequestMapping *) * *(..))")
public void loggingStartPointRequests(JoinPoint joinPoint) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
}
@After("execution(@(@org.springframework.web.bind.annotation.RequestMapping *) * *(..))")
public void loggingEndPointRequests(JoinPoint joinPoint) throws IOException {
}
}
Run Code Online (Sandbox Code Playgroud)
我的控制器类:
@RestController
public class MainController {
@GetMapping("/people") //
public ResponseEntity<Poeple> getAllPeople(@RequestParam(name = "page", required = false) Integer page,
@RequestParam(name = …Run Code Online (Sandbox Code Playgroud) 我正在学习 AspectJ 注释,我认为 @After 注释在 @AfterThrowing 注释之前执行。但相反,它在它之后执行。为什么?
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect
@Component
@Order(2)
public class MyDemoLoggingAspect {
@After("execution(* com.luv2code.aopdemo.dao.AccountDAO.findAccounts(..))")
public void afterFinallyFindAccountsAdvice(JoinPoint theJoinPoint) {
// print out which method we are advising on
String method = theJoinPoint.getSignature().toShortString();
System.out.println("\n=====>>> Executing @After (finally) on method: "
+ method);
}
@AfterThrowing(
pointcut="execution(* com.luv2code.aopdemo.dao.AccountDAO.findAccounts(..))",
throwing="theExc")
public void afterThrowingFindAccountsAdvice(
JoinPoint theJoinPoint, Throwable theExc) {
// print out which method we …Run Code Online (Sandbox Code Playgroud) package com.nit.aop.advices;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class LoggingBeforeAdvice implements MethodBeforeAdvice
{
@Override
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
// TODO Auto-generated method stub
}
}
Run Code Online (Sandbox Code Playgroud)
当我执行这个程序时,我得到错误 - "ClassName类型的层次结构是不一致的"所以现在我想删除此错误
我试图了解一个涉及 spring 声明性事务注释的项目。该函数的主体没有进行任何 JDBC 调用或调用 JPA 存储库方法。它所做的只是调用一些第三方 API 并转换它的结果,它甚至没有将响应保存在数据库中。所以根本没有数据库交互。
我的问题是是否值得在此方法上使用 @Transactional 注释?因为根据我的理解,@Transactional 仅有助于保持数据库的一致性。
我有任务以某种方式监视 logback 库中的方法调用。我开始用 spring aop 做这件事。因此,例如,我应该在 ch.qos.logback.classic.Logger 类中捕获所有方法的执行。这是我的方面:
@Aspect
@Configuration
public class LogbackAspect {
@Before(value = "execution(* ch.qos.logback.classic.Logger.*(..))")
public void getInfo(JoinPoint joinPoint) {
System.out.println("+++++AOP " + joinPoint.getSignature().getName());
}
}
Run Code Online (Sandbox Code Playgroud)
但是暂时不行,那么,有没有可能用spring aop拦截方法执行呢?或者有一些更好的方法来做到这一点?
我是Java/Spring的新手.我需要从配置中读取一些值,但如果它不存在则应该失败.现在我有以下代码:
public class SomeClass {
@Value("${some.property:#{null}}")
private String someProperty;
public void someMethod() throws Exception {
if (someProperty == null) throw new AopConfigException("The property must be set");
}
}
Run Code Online (Sandbox Code Playgroud)
它工作正常,但我需要添加额外的if块.我可以写那样的东西吗?
@Value("${some.property:#{throw new AopConfigException(\"The property must be set\")}}")
private String someProperty;
Run Code Online (Sandbox Code Playgroud)
要么
@Value("${some.property:#{throwException()}}")
private String someProperty;
private static void throwException() {
throw new AopConfigException("The property must be set");
}
Run Code Online (Sandbox Code Playgroud)
立即失败
更新:
如果我没有使用下面建议的某个默认值,那么它对我来说仍然不会失败.我没有java.lang.IllegalArgumentException: