#EnableAspectJAutoProxy does not work - java

I am using Spring Boot, and I would like to use AspectJ with it.
The following works (of course):
#Aspect
#Component
public class RequestMappingAspect {
#Before("#annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void advice(JoinPoint joinPoint) {
...
}
}
However, if #Component is removed and #EnableAspectJAutoProxy is added, the following does not work.
#SpringBootApplication
#EnableSwagger2
#EnableAspectJAutoProxy
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
How to enable AspectJ auto proxy correctly?

Wondering about the same thing, we ended up doing something similar to this:
#EnableAspectJAutoProxy(proxyTargetClass = true)
#Configuration("Main applicationContext")
#ComponentScan(
basePackages = {"com.where.ever"},
excludeFilters = {#ComponentScan.Filter(Aspect.class)})
public class ApplicationConfiguration {
#Bean(autowire = Autowire.BY_TYPE)
public SomeAspect someAspect() {
return Aspects.aspectOf(SomeAspect.class);
}
...
...
}
This enabled us to just add the #Aspect-annotation on the aspects, which also wired them correctly.
Might be that this was a pointless reply, however, it explains how we solved the issue - and not the actual solution to the problem. Let me know if you want this to be deleted.

You need both #EnableAspectJAutoProxy for the spring configuration and combination of #Aspect / #Component annotations
#EnableAspectJAutoProxy does the same thing as xml based <aop:aspectj-autoproxy>

Related

Override HystrixCommandAspect bean in spring-cloud-netflix-hystrix

The HystrixCommandAspect bean is declared in the HystrixCircuitBreakerConfiguration class but I would like to use my own custom implementation of HystrixCommandAspect and inject a different bean.
Application:
#SpringBootApplication
#EnableAspectJAutoProxy
#EnableCircuitBreaker
#Import(HystrixConfiguration.class)
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Configuration:
#Configuration
public class HystrixConfiguration {
#Bean
#Primary
public HystrixCommandAspect hystrixCommandAspect(){
return new com.hystrix.HystrixCommandAspect();
}
}
Custom HystrixCommandAspect:
package com.hystrix;
#Aspect
public class HystrixCommandAspect extends com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect {
...
}
However, when I use the annotation #EnableCircuitBreaker it uses the HystrixCircuitBreakerConfiguration and doesn't even load my own #Bean definition.
I upgraded spring to the latest release and this fixed the problem. I also noticed in the logs that it said it was overriding the bean provided in HystrixCircuitBreakerConfiguration.

Are there anyway to disable annotation in spring4?

I have a question, maybe simple, but I can not find out the solution.
I am using spring boot and added some annotation to the code like this:
#EnableEurekaClient
#SpringBootApplication
#EnableCaching
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
But in some other environment, for example, in production environment, we want to remove EurekaClient, but I do not want to manually remove it manually for each environment, instead, I want to use environment variable or command line parameter to control the behavior. I suppose to do this way:
#EnableEurekaClient(Enabled = {EnableEureka})
#SpringBootApplication
#EnableCaching
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Then I can easily start this application without touching the code.
Can anyone tell me if this is possible? If so, how can I do it?
Thanks
You would want to work with Spring Boot Profiles. Split out the #EnableEurekaClient to another #Configuration class and also add an #Profile("eureka-client") to the class. Then when starting up the application you can set a -Dspring.profiles.active=eureka-client for the environments other than production.
Example:
#SpringBootApplication
#EnableCaching
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
#Configuration
#EnableEurekaClient
#Profile("eureka-client")
public class EurekaClientConfiguration {
}
I prefer this method as you don't have to create an extra profile:
#Configuration
#EnableEurekaClient
#ConditionalOnProperty(name = "application.enabled", havingValue = "true", matchIfMissing = false)
public class EurekaClientConfiguration {
}

#ComponentScan doesn't work in Spring boot AutoConfiguration class?

I am trying to create a new starter. I have a business module, say ProjectManager, that contains some classes annotated with #Component. Following the tutorial, I created an autoconfigure module, it contains an AutoConfiguration class. Firstly, I tried to use #ComponentSan to find the beans in my business module.
#ComponentScan(value = {"com.foo.project"})
#ConditionalOnClass({Project.class})
#Configuration
public class ProjectAutoConfiguration {
....
}
But it doesn't work. I have to add additional configuration class as below:
#Configuration
#ComponentScan(value = {"com.foo.project"})
#MapperScan(value = {"com.foo.project"})
public class ProjectConfig {
}
And then import it into AutoConfiguration class like below:
#Import(ProjectConfig.class)
#ConditionalOnClass({Project.class})
#Configuration
public class ProjectAutoConfiguration {
....
}
That works. But according to the spring doc.
auto-configuration is implemented with standard #Configuration classes
So my question is, Why #ComponentScan doesn't work here ? Did I make something wrong? Or it is by design ?
you have to use the compentscan annotation into the main class. Here a sample code:
#SpringBootApplication
#ComponentScan("com.foo.project")
public class MainApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MainApplication.class);
}
public static void main(String[] args) {
new MainApplication().configure(new SpringApplicationBuilder(MainApplication.class)).run(args);
}
}
Cheers
Automatic everything requires the Application class (annotated with #SpringBootApplication) to be in a "higher" package than the components you want to scan.
Use:
package com.example.foo;
for your application and put components in a package like:
package com.example.foo.entities;
See also https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-using-springbootapplication-annotation.html
Can you try with following?
#ConditionalOnClass({Project.class})
#Configuration
#EnableAutoConfiguration
#ComponentScan(value = {"com.foo.project"})
public class ProjectAutoConfiguration {
....
}
I was developing a SDK project. It needs the application which depends on the SDK to scan for beans beneath specific package in the SDK during start period.
Anotate with #ComponentScan on autowire configuration class doesn't take effect.
Then I am trying to use #Import annotation to import a class implemented interface ImportBeanDefinitionRegistrar(Interface to be implemented by types that register additional bean definitions when processing #Configuration classes. Useful when operating at the bean definition level (as opposed to #Bean method/instance level) is desired or necessary).
Within ImportBeanDefinitionRegistrar implementation class, I register a class annotated with #ComponentScan as bean. Run application again, it works as expected.
Codes below:
AutoConfiguration Class:
#Configuration
#Import(TestConfigRegistar.Registrar.class)
public class TestClientAutoCofiguration {
}
Registar class:
public class TestConfigRegistar {
public static class Registrar implements ImportBeanDefinitionRegistrar {
private static final String BEAN_NAME = "componentScanConfig";
#Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata,
BeanDefinitionRegistry registry) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(ComponentScanConfig.class);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
}
}
}
Class with #ComponentScan annotation
// Leave an empty value of #ComponentScan will let spring scan
// current class package and all sub-packages
#ComponentScan
public class ComponentScanConfig {
}
I believe that the point is that beans annotated with #ComponentScan must be defined at definition level (as opposed to #Bean method/instance level). Please correct me if I'm wrong, Thanks.

How can I programmatically configure Spring's #Configuration annotations?

Specifically, I would like to be able share configuration classes by instantiating them and including them. Where you would normally do this:
#Configuration
#Import({SharedConfiguration.class})
public class MyAppContext extends WebMvcConfigurerAdapter {
//stuff
}
#Configuration
#ComponentScan("com.example")
public class SharedConfiguration {
//stuff
}
I would like to do this:
#Configuration
public class MyAppContext extends WebMvcConfigurerAdapter {
public SharedConfiguration sharedConfig(){
return new SharedConfiguration("com.example");
}
//stuff
}
#Configuration
public class SharedConfiguration {
public SharedConfiguration(String package){
//tell Spring to scan package
}
}
The reason for this is that I need to be able to tell the shared component doing the scan what package to look at. It will different depending on what project it is being used in.
EDIT:
To provide some additional context, I'm trying to make a general-use configuration for setting up Hibernate and EHCache using our external configuration provider that several projects can use. I'm certainly open to other methods to doing this, but this seemed like the most logical path to me. I'm sure there's ~something~ in Spring that I can fiddle with to say, "Here! Scan this path when Spring initializes you!" instead of hard-coding it into an annotation.
You can take advantage of property sources in this case.
In the test case, I am setting a system property that is picked up by the Spring property source configuration -
#RunWith(SpringRunner.class)
#ContextConfiguration
public class MyAppContextTest {
#Autowired
ApplicationContext context;
#BeforeClass
public static void beforeClass() {
// use a system property to configure the component scan location of the SharedConfiguration
// where the "ExampleBean" lives
System.setProperty("packages", "net.savantly.other.packages");
}
#Test
public void ensureExampleBeanExists() {
// throws exception if it doesnt exist
context.getBean(ExampleBean.class);
}
#Configuration
#Import(MyAppContext.class)
static class TestContext {
}
}
Using the Spring expression language in the ComponentScan -
#Configuration
#ComponentScan("${packages}")
public class SharedConfiguration {}
Other Referenced Classes -
#Configuration
#Import(SharedConfiguration.class)
public class MyAppContext extends WebMvcConfigurerAdapter {
#Autowired
SharedConfiguration sharedConfig;
//stuff
}
#Service
public class ExampleBean {
}

#ComponentScan not working in test with spring-boot-starter-test

I am attempting to test my #Service and #Repository classes in my project with spring-boot-starter-test and #Autowired is not working for the classes I'm testing.
Unit test:
#RunWith(SpringRunner.class)
#SpringBootTest
#ContextConfiguration(classes = HelloWorldConfiguration.class
//#SpringApplicationConfiguration(classes = HelloWorldRs.class)
//#ComponentScan(basePackages = {"com.me.sbworkshop", "com.me.sbworkshop.service"})
//#ConfigurationProperties("helloworld")
//#EnableAutoConfiguration
//#ActiveProfiles("test")
// THIS CLASS IS IN src/test/java/ AND BUILDS INTO target/test-classes
public class HelloWorldTest {
#Autowired
HelloWorldMessageService helloWorldMessageService;
public static final String EXPECTED = "je pense donc je suis-TESTING123";
#Test
public void testGetMessage() {
String result = helloWorldMessageService.getMessage();
Assert.assertEquals(EXPECTED, result);
}
}
Service:
#Service
#ConfigurationProperties("helloworld")
// THIS CLASS IS IN /src/main/java AND BUILDS INTO target/classes
public class HelloWorldMessageService {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message=message;
}
}
The commented class annotations on the unit test represent the various things I've tried to get this working. The test and the project packages are in the same package paths and the #ComponentScan works fine from my entry point (#RestController class with main method). The service #ComponentScan's and #Autowire's fine in my #RestController class in the src/main/java side, but does not in the test. I am required to add it again as a #Bean in my #Configuration class in order for #Autowired to work. The class is otherwise in scope just fine and I can reference and instantiate it just fine from the test. The problem appears to be that #ComponentScan does not appear to correctly traverse multiple entries in my test runner classpath, in this case /target/test-classes and /target/classes.
The IDE I am using is IntelliJ IDEA 13.
UPDATE - here are HelloWorldRs and its config:
#RestController
#EnableAutoConfiguration
#ComponentScan
public class HelloWorldRs {
// SPRING BOOT ENTRY POINT - main() method
public static void main(String[] args) {
SpringApplication.run(HelloWorldRs.class);
}
#Autowired
HelloWorldMessageService helloWorldMessageService;
#RequestMapping("/helloWorld")
public String helloWorld() {
return helloWorldMessageService.getMessage();
}
}
...
#Configuration
public class HelloWorldConfiguration {
#Bean
public Map<String, String> map() {
return new HashMap<>();
}
// This bean was manually added as a workaround to the #ComponentScan problem
#Bean
public HelloWorldMessageService helloWorldMessageService() {
return new HelloWorldMessageService();
}
// This bean was manually added as a workaround to the #ComponentScan problem
#Bean
public HelloWorldRs helloWorldRs() {
return new HelloWorldRs();
}
}
First, I'd recommend to use a newer #RunWith(SpringRunner.class) but that makes no difference, it is just shorter (and recommended).
Second, from the #EnableAutoConfiguration I see that you are using spring boot - which is certainly a good thing. There are some good reasons why not to use #ComponentScan directly. Can you try the following?
#RunWith(SpringRunner.class)
#SpringBootTest
#ContextConfiguration(classes=YourApplication_or_other_Configuration.class)
public class HelloWorldTest {
... etc.
I don't know if this will turn out to be the solution, but don't use the default package (i.e. don't put *.java in "src/main/java" directly), and definitely don't use a #ComponentScan or #EnableAutoConfiguration in the default package. You will end up killing your application on startup as it tries to scan everything on the classpath (including all the Spring libraries).
SpringBoot 2.7.3, JUnit 5.8.2
If you want to have full control about the spring's configuration (and not rely on the hidden magic of auto configuration) I suggest to create an explicit configuration class:
#ComponentScan(basePackages = { "my.package.to.scan" })
public class MySpringTestConfig
{
// just for spring configuration annotations
}
and reference it in your test class:
#ContextConfiguration(classes = { MySpringTestConfig.class })
#ExtendWith({ SpringExtension.class })
class MySpringTest
{
...
}

Categories