为什么在使用 Spring AOP 时 属性 值为空,但通过 getter 可以使用相同的值?
Why is the property value null when using Spring AOP but the same value works via getter?
我了解到使用 AOP 时会创建一个代理 bean。我不明白为什么我不能在我的 main 方法中直接访问 属性?我们在使用AOP时是否总是必须使用方法来获取值?
package power.sam;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import river.sam.Ganga;
import javax.inject.Inject;
import java.util.stream.Stream;
@Slf4j
@ComponentScan(basePackages = {"power.sam"})
@EnableAspectJAutoProxy
@Data
public class MyTest {
Employee emp;
@Autowired
MyTest(Employee emp){
this.emp = emp;
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyTest.class);
context.registerShutdownHook();
MyTest bean = (MyTest) context.getBean("myTest");
log.info("Bean is {}", bean);
log.info("Bean.Employee via getter is {}", bean.getEmp());
log.info("Bean.Employee via property is {}", bean.emp);
}
}
输出
14:51:12.925 [main] 信息 power.sam.MyTest - Bean 是 MyTest(emp=power.sam.Employee@3700ec9c)
14:51:12.955 [main] INFO power.sam.MyTest - Bean.Employee 通过 get 是 power.sam.Employee@3700ec9c
14:51:12.955 [main] 信息 power.sam.MyTest - Bean.Employee 通过 属性 为空
更新:这似乎只有在我有像
这样的所有方法建议时才会发生
@Before("execution(public * *(..))")
要清楚地了解后台发生的情况,请将以下内容添加到测试代码中。
System.out.println("Bean.Employee runtime class is "+ bean.getClass());
完整的main方法如下
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyTest.class);
context.registerShutdownHook();
MyTest bean = (MyTest) context.getBean("myTest");
System.out.println("Bean is "+ bean);
System.out.println("Bean.Employee via getter is "+ bean.getEmp());
System.out.println("Bean.Employee runtime class is "+ bean.getClass());
System.out.println("Bean.Employee via property is "+ bean.emp);
}
现在当 运行 的切入点表达式为:@Before("execution(public * *(..))")
控制台日志为
Bean is rg.so.qn64919052.MyTest@662f5666
Bean.Employee via getter is rg.so.qn64919052.entity.Employee@75ed9710
Bean.Employee runtime class is class rg.so.qn64919052.MyTest$$EnhancerBySpringCGLIB$e53892a
Bean.Employee via property is null
注意:bean.getClass()
返回了创建的代理对象的 class。
为了清楚起见,Employee
class 是在包 rg.so.qn64919052.entity
中创建的,现在 运行 的切入点表达式为:@Before("execution(public * rg.so.qn64919052.entity.Employee.*(..))")
控制台日志为
Bean is rg.so.qn64919052.MyTest@acdb094
Bean.Employee via getter is rg.so.qn64919052.entity.Employee@674bd420
Bean.Employee runtime class is class rg.so.qn64919052.MyTest
Bean.Employee via property is rg.so.qn64919052.entity.Employee@674bd420
注意:bean.getClass()
返回原始 class。
解释:
Spring AOP 是基于代理的。动态代理只继承方法,不继承任何实例变量。
第一个 运行 中的切入点表达式具有全局作用域,它将建议所有 Spring bean 的 public(受保护和包作用域,自 CGLIB 起)方法执行.为此,创建了 MyTest 的代理。
第二个 运行 中的切入点表达式的范围有限 (rg.so.qn64919052.entity.Employee.*
),MyTest 未被代理。
参考资料:
我了解到使用 AOP 时会创建一个代理 bean。我不明白为什么我不能在我的 main 方法中直接访问 属性?我们在使用AOP时是否总是必须使用方法来获取值?
package power.sam;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import river.sam.Ganga;
import javax.inject.Inject;
import java.util.stream.Stream;
@Slf4j
@ComponentScan(basePackages = {"power.sam"})
@EnableAspectJAutoProxy
@Data
public class MyTest {
Employee emp;
@Autowired
MyTest(Employee emp){
this.emp = emp;
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyTest.class);
context.registerShutdownHook();
MyTest bean = (MyTest) context.getBean("myTest");
log.info("Bean is {}", bean);
log.info("Bean.Employee via getter is {}", bean.getEmp());
log.info("Bean.Employee via property is {}", bean.emp);
}
}
输出
14:51:12.925 [main] 信息 power.sam.MyTest - Bean 是 MyTest(emp=power.sam.Employee@3700ec9c)
14:51:12.955 [main] INFO power.sam.MyTest - Bean.Employee 通过 get 是 power.sam.Employee@3700ec9c
14:51:12.955 [main] 信息 power.sam.MyTest - Bean.Employee 通过 属性 为空
更新:这似乎只有在我有像
这样的所有方法建议时才会发生@Before("execution(public * *(..))")
要清楚地了解后台发生的情况,请将以下内容添加到测试代码中。
System.out.println("Bean.Employee runtime class is "+ bean.getClass());
完整的main方法如下
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyTest.class);
context.registerShutdownHook();
MyTest bean = (MyTest) context.getBean("myTest");
System.out.println("Bean is "+ bean);
System.out.println("Bean.Employee via getter is "+ bean.getEmp());
System.out.println("Bean.Employee runtime class is "+ bean.getClass());
System.out.println("Bean.Employee via property is "+ bean.emp);
}
现在当 运行 的切入点表达式为:@Before("execution(public * *(..))")
控制台日志为
Bean is rg.so.qn64919052.MyTest@662f5666
Bean.Employee via getter is rg.so.qn64919052.entity.Employee@75ed9710
Bean.Employee runtime class is class rg.so.qn64919052.MyTest$$EnhancerBySpringCGLIB$e53892a
Bean.Employee via property is null
注意:bean.getClass()
返回了创建的代理对象的 class。
为了清楚起见,Employee
class 是在包 rg.so.qn64919052.entity
中创建的,现在 运行 的切入点表达式为:@Before("execution(public * rg.so.qn64919052.entity.Employee.*(..))")
控制台日志为
Bean is rg.so.qn64919052.MyTest@acdb094
Bean.Employee via getter is rg.so.qn64919052.entity.Employee@674bd420
Bean.Employee runtime class is class rg.so.qn64919052.MyTest
Bean.Employee via property is rg.so.qn64919052.entity.Employee@674bd420
注意:bean.getClass()
返回原始 class。
解释:
Spring AOP 是基于代理的。动态代理只继承方法,不继承任何实例变量。
第一个 运行 中的切入点表达式具有全局作用域,它将建议所有 Spring bean 的 public(受保护和包作用域,自 CGLIB 起)方法执行.为此,创建了 MyTest 的代理。
第二个 运行 中的切入点表达式的范围有限 (rg.so.qn64919052.entity.Employee.*
),MyTest 未被代理。
参考资料: