A1 , @ComponentScan
не работает, поскольку он закомментирован из "Классы компонентов, используемые для загрузки ApplicationContext." или PersonOperationsConfigClass
@Configuration
//@ComponentScan(basePackages = {"samples.chapter3"})
@EnableAspectJAutoProxy
public class PersonOperationsConfigClass {}
Тестовый класс получает ApplicationContext, созданный из классов компонентов, указанных в аннотации @ ContextConfiguration . Поскольку никакие компоненты не были созданы или были автоматически обнаружены, @Autowired
не удалось.
Когда AnnotationConfigApplicationContext
использовался в методе, помеченном @Before
, ApplicationContext был создан программным путем. ctx.scan("samples.chapter3");
отсканирован и обнаружен автоматически PersonOperations
с комментариями @Component
. obj
ссылка установлена с кодом obj = ctx.getBean(PersonOperationsI.class);
. Этот объект не был 'Autowired' .
Обновление на основе комментария от OP
Аннотации Junit 4 и @ExtendWith (SpringExtension. класс) комбинация не работает для меня.
Следующий класс Test успешно работает без ошибок / сбоев. obj
имеет автоматическую связь и не является нулевым. Я использовал соответствующие аннотации от Junit 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
имеет значение по умолчанию "false" для атрибута proxyTargetClass
. Этот атрибут определяет механизм прокси: прокси JDK (false) или прокси CGLIB (true).
Здесь наличие действительного аспекта с действительным советом приводит к тому, что фактический прокси включается. Компонент будет проксироваться только тогда, когда совет оказывает какое-либо влияние на него. Короче говоря, проксирование компонента происходит только при необходимости.
Дело 1
Когда: @EnableAspectJAutoProxy
/ @EnableAspectJAutoProxy(proxyTargetClass = false )
ctx.getBean(InterfaceType)
возвращает bean-компонент ctx.getBean(ImplementationClassType)
не может вернуть bean-компонент
Case 2
Когда: @EnableAspectJAutoProxy(proxyTargetClass = true )
ctx.getBean(InterfaceType)
возвращает бин ctx.getBean(ImplementationClassType)
возвращает бин
Случай 3
Когда : @EnableAspectJAutoProxy
аннотация отсутствует
ctx.getBean(InterfaceType)
возвращает бин ctx.getBean(ImplementationClassType)
возвращает бин
Случай 1 Spring AOP включен с proxyTargetClass
как false. JDK-прокси создает прокси-компонент типа Интерфейс. Созданный компонент имеет тип InterfaceType , а не ImplementClassType . Это объясняет, почему ctx.getBean (ImplementClassType) не может вернуть bean-компонент.
Случай 2 , Spring AOP включен с proxyTargetClass
как true. CGLIB создает прокси-компонент путем создания подкласса класса, помеченного @Component
. Созданный компонент имеет тип ImplementClassType , а также квалифицируется как InterfaceType . Таким образом, оба вызова getBean () возвращают этот bean-компонент успешно.
Case 3 ,
Spring создает объекты "proxy" только в том случае, если требуется какая-либо специальная обработка (например, AOP , Управление транзакциями).
Теперь с этой логикой c, поскольку @EnableAspectJAutoProxy
отсутствует, создается компонент для класса, помеченного @Component
, без прокси. Созданный компонент имеет тип ImplementClassType , а также квалифицируется как InterfaceType . Таким образом, оба вызова getBean () возвращают этот компонент успешно.
Анализ выполнен с использованием следующего кода.
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
Надеюсь, это поможет