gpt4 book ai didi

Java aop ComponentScan 不工作 & AnnotationConfigApplicationContext getBean 不工作

转载 作者:行者123 更新时间:2023-12-02 21:57:00 33 4
gpt4 key购买 nike

我编写了一组简单的类来向 friend 展示如何使用 Annotations for AOP(而不是 xml 配置)。我们无法让 @ComponentScan 工作,并且 AnnotationConfigApplicationContext getBean 行为也很不正常。我想了解两件事。请参阅下面的代码:

PersonOperationsI.java

package samples.chapter3;

import org.springframework.stereotype.Component;

@Component
public interface PersonOperationsI {

public String getName();

}

PersonOperations.java
/**
*
*/
package samples.chapter3;

import org.springframework.stereotype.Component;

@Component
public class PersonOperations implements PersonOperationsI {


public String getName() {
return "";
}

}

PersonOperationsConfigClass.java
package samples.chapter3;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
//question2 - Below Component Scan didnt work - Test Case failing in setup()
//@ComponentScan(basePackages = {"samples.chapter3"})
@EnableAspectJAutoProxy

public class PersonOperationsConfigClass {

}

PersonOperationsAdvice.java
/**
*
*/
package samples.chapter3;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class PersonOperationsAdvice {

/**
* execution( [Modifiers] [ReturnType] [FullClassName].[MethodName]
([Arguments]) throws [ExceptionType])

* @param joinPoint
* @return
*/
@Before("execution(public * samples.chapter3.PersonOperations.getName()))")
public String beforeGetName(JoinPoint joinPoint) {
System.out.println("method name = " + joinPoint.getSignature().getName());
return null;
}
}

PersonOperationsTest.java
package samples.chapter3;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = { PersonOperationsConfigClass.class })
public class PersonOperationsTest {

//@Autowired
private PersonOperationsI obj;

@Before
public void setUp() {

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("samples.chapter3");
ctx.refresh();
obj = ctx.getBean(PersonOperationsI.class);
//obj = ctx.getBean(PersonOperations.class);//getBean of Child class not working - why ?

Assert.assertNotNull(obj);
ctx.close();
}

@Test
public void test() {
System.out.println(obj.getName());
}

}

问题1 - 为什么@componentscan 不起作用。如果我不在测试用例中使用 AnnotationConfigApplicationContext 而只依赖@componentscan & autowired - 测试用例中的对象为空

Question2 - ctx.getBean(PersonOperations.class);//子类的getBean不起作用 - 为什么?

最佳答案

A1 , @ComponentScan没用,因为它被 "The component classes to use for loading an ApplicationContext." 注释掉了或 PersonOperationsConfigClass

@Configuration
//@ComponentScan(basePackages = {"samples.chapter3"})
@EnableAspectJAutoProxy

public class PersonOperationsConfigClass {}

测试类获取由 @ContextConfiguration 指定的组件类创建的 ApplicationContext注解。由于没有创建或自动检测到任何组件, @Autowired失败的。

AnnotationConfigApplicationContext在带有 @Before 注释的方法中使用,以编程方式创建了一个 ApplicationContext。 ctx.scan("samples.chapter3");扫描并自动检测 PersonOperations注释为 @Component . obj使用代码 obj = ctx.getBean(PersonOperationsI.class); 设置引用.该对象不是“ Autowiring ”的。

根据 OP 的评论进行更新

Junit 4 注释和 @ExtendWith(SpringExtension.class) 组合对我不起作用。

以下测试类以零错误/失败成功运行。 obj是 Autowiring 的,不为空。我用了对应的 annotations从 6 月 5 日开始。
package rg.app.aop.so.q1;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes= {PersonOperationsConfigClass.class})
public class PersonOperationsTest {

@Autowired
private PersonOperationsI obj;

@BeforeEach
public void setUp() {
System.out.println("init ::"+ obj);
Assertions.assertNotNull(obj);
}

@Test
public void testPersonOps() {
Assertions.assertNotNull(obj);
}
}

配置类
package rg.app.aop.so.q1;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = {"rg.app.aop.so.q1"})
public class PersonOperationsConfigClass {

}

A2,
以下是我的分析。

记住, @EnableAspectJAutoProxy proxyTargetClass 的默认值“false”属性。此属性决定代理机制:JDK 代理 (false) 或 CGLIB 代理 (true)。

这里存在一个有效的 Aspect 和一个有效的通知会导致实际的代理启动。只有当通知对组件有任何影响时,组件才会被代理。简而言之,组件的代理仅在需要时发生。

案例一

时间: @EnableAspectJAutoProxy/ @EnableAspectJAutoProxy(proxyTargetClass = false )
  • ctx.getBean(InterfaceType)返回一个 bean
  • ctx.getBean(ImplementationClassType)无法返回 bean

  • 案例二

    时间: @EnableAspectJAutoProxy(proxyTargetClass = true )
  • ctx.getBean(InterfaceType)返回一个 bean
  • ctx.getBean(ImplementationClassType)返回一个 bean

  • 案例3

    时间: @EnableAspectJAutoProxy没有注释
  • ctx.getBean(InterfaceType)返回一个 bean
  • ctx.getBean(ImplementationClassType)返回一个 bean

  • 案例一 , Spring AOP 通过 proxyTargetClass 启用作为假。 JDK 代理创建一个接口(interface)类型的代理 bean。
    创建的 bean 的类型是 InterfaceType 而不是 ImplementationClassType。这解释了为什么 ctx.getBean(ImplementationClassType) 无法返回 bean。

    案例二 , Spring AOP 通过 proxyTargetClass 启用一样真实。 CGLIB 通过子类化带有 @Component 注释的类来创建代理 bean。 .
    创建的 bean 是 ImplementationClassType 类型,也符合 InterfaceType 的要求。所以这两个 getBean() 调用都成功返回了这个 bean。

    案例3 ,

    如果需要任何特殊处理(例如:AOP、事务管理),Spring 只会创建“代理”对象。

    现在有了这个逻辑,因为 @EnableAspectJAutoProxy如果不存在,则会为带有 @Component 注释的类创建一个 bean没有任何代理。
    创建的 bean 是 ImplementationClassType 类型,也符合 InterfaceType 的要求。所以这两个 getBean() 调用都成功返回了这个 bean。

    使用以下代码完成分析。
    package rg.app.aop.so.q1;

    import org.springframework.context.annotation.AnnotationConfigApplicationContext;

    public class AppMain {

    public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.scan("rg.app.aop.so.q1");
    ctx.refresh();
    System.out.println();
    for(String name:ctx.getBeanNamesForType(PersonOperationsI.class)) {
    System.out.println(name);
    }
    for(String name:ctx.getBeanNamesForType(PersonOperations.class)) {
    System.out.println(name);
    }
    PersonOperationsI obj = ctx.getBean(PersonOperationsI.class);
    System.out.println(obj.getClass());

    obj = ctx.getBean(PersonOperations.class);
    System.out.println(obj.getClass());
    ctx.registerShutdownHook();

    }

    }

    案例 1 打印

    personOperations
    class com.sun.proxy.$Proxy18
    Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'rg.app.aop.so.q1.PersonOperations' available

    案例 2 打印

    personOperations
    personOperations
    class rg.app.aop.so.q1.PersonOperations$$EnhancerBySpringCGLIB$$c179e7f2
    class rg.app.aop.so.q1.PersonOperations$$EnhancerBySpringCGLIB$$c179e7f2

    案例 3 打印

    personOperations
    personOperations
    class rg.app.aop.so.q1.PersonOperations
    class rg.app.aop.so.q1.PersonOperations

    希望这可以帮助

    关于Java aop ComponentScan 不工作 & AnnotationConfigApplicationContext getBean 不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59763488/

    33 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com