Override HystrixCommandAspect bean in spring-cloud-netflix-hystrix - java

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.

Related

Spring : Cannot get value from application.properties

I created Spring project via Spring Initializr with project following struct:
I defined property in application.properties file :
my.prop=testvalue
I inject this value into MyClass as following :
#Component
class MyClass {
#Value("${my.prop}")
private String myProp;
public String getMyProp() {
return myProp;
}
}
ConfigBeans defined as following:
package com.example.propertiesdemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ConfigBeans {
#Bean
public MyClass myLitoBean() {
return new MyClass();
}
}
PropertiesdemoApplication.java :
package com.example.propertiesdemo;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
#SpringBootApplication
public class PropertiesdemoApplication {
public static void main(String[] args) {
ApplicationContext context
= new AnnotationConfigApplicationContext(
ConfigBeans.class);
MyClass myClass = context.getBean(MyClass.class);
System.out.println(myClass.getMyProp());
}
}
I am expecting that after executing line
System.out.println(myClass.getMyProp());
will be printed value of myprop defined in application.properties (i.e testvalue), but after running (via Netbeans IDE) I get output :
${my.prop}
What was missed / wromg in this code ? Thanks in advance
You are creating MyClass bean twice.
Using #component annotation
using #bean annotation in the config class (use method name lowerCamelCase i.e. in your case myClass())
Create bean only once using any one of the above.
You dont need to create an application context in the main method like this. The presented code is a kind of mixture of "traditional" spring and spring boot. So you're kind of bypassing all the goodies that spring boot offers, among which is automatic application.properties loading.
If you're using spring boot (there is a #SpringBootApplication annotation) then it will create everything by itself.
Usually it should be something like this
public static void main(String[] args) {
SpringApplication.run(PropertiesdemoApplication.class, args);
}
Right, as Navnath Adsul said, you need the bean to be created once, and also, since you are using Spring Boot, you need to raise the context using a special method
#SpringBootApplication
public class PropertiesdemoApplication implements CommandLineRunner {
// Inject Bean
#Autowired
private MyClass myClass;
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(PropertiesdemoApplication.class)
.run(args);
// or SpringApplication.run(PropertiesdemoApplication.class, args);
}
#Override
public void run(String[] args) throws Exception {
System.out.println(myClass.getMyProp());
}
}
#SpringBootApplication
public class PropertiesdemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(PropertiesdemoApplication.class, args);
MyClass myClass = context.getBean(MyClass.class);
System.out.println(myClass.getMyProp());
}
}

Overriding configuration is spring

Here is my situation. I have a parent project which has a bean configuration as follows
#Configuration
public class Configuration {
#Bean
public BeanA beanA(#Autowired BeanB beanB) {
return new BeanA(beanB);
}
I want to override this configuration, because I need to override some of the definitions on BeanB.
#Configuration
public class Configuration {
#Bean
public BeanA beanA(#Autowired BeanC beanC) {
return new BeanA(beanC);
}
Where my bean of type C
public class BeanC extends BeanB { ... }
But when I run the application, I am always getting the configuration coming from the parent. Also have enabled the bean-definition-overriding
spring.main.allow-bean-definition-overriding=true
Does anyone knows how can I tell the spring container to use my bean definition instead the one that is coming from my parent project.
Thanks in advance!
You can annotate your bean with #Primary annotation (see: https://www.baeldung.com/spring-primary)
#Configuration
public class Configuration {
#Primary
#Bean
public BeanA beanA(#Autowired BeanC beanC) {
return new BeanA(beanC);
}

Spring inherited #Component with constructor arguments

I have a service which needs to create Agents on the runtime. Agents inherit from a base Agent class. I would like to use the Autowired ability of spring instead of doing my own dependency injections.
But I am running into this issue, even though I am marking the component as scope=prototype, and even #Lazy to prevent anything from happening at compile-time.
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.my.project.AgentType1 required a bean of type 'com.my.project.POJO' that could not be found.
This is the service that tries to create the agents:
#Service
public class ProjectMain {
#Autowired
ApplicationContext context;
List<IAgent> agents = new ArrayList<>();
void SetupAgents(List<POJO> agentPojos) {
for(POJO agentPojo: agentPojos) {
IAgent agent = AgentFactory.CreateAgent(agentPojo, context);
agents.add(agent);
}
}
}
This is the factory class, not marked as #Component etc. It uses the context passed to it to create the child class beans. It tries to pass the constructor argument via the getBean method.
public class AgentFactory {
public static IAgent CreateAgent(POJO agentPojo, ApplicationContext context) {
if (agentPojo.type.equals("AgentType1")) {
return context.getBean(AgentType1.class, agentPojo);
} else {
return context.getBean(AgentType2.class, agentPojo);
}
}
}
This is a custom annotation which I found is needed for inheritance scenarios.
#Target({ ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Component
#Inherited
#Lazy
#Scope("prototype")
public #interface AgentAnnotation {}
These are the base and child agent classes, which need a custom data structure called POJO to work.
#AgentAnnotation
public class BaseAgent implements IAgent {
#Autowired
Environment env;
public BaseAgent(POJO agentPojo, String someotherdata) {
}
}
public class AgentType1 extends BaseAgent {
public AgentType1(POJO agentPojo) {
super(agentPojo, "mydata1");
...
}
}
public class AgentType2 extends BaseAgent {
public AgentType2(POJO agentPojo) {
super(agentPojo, "mydata2");
...
}
}
This is the starter app.
#ComponentScan(basePackages = "com.my.project", includeFilters = #ComponentScan.Filter(AgentAnnotation.class))
#EnableScheduling
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
I also tried the configuration approach:
#Configuration
public class BaseAgentConfig {
#Bean
#Scope("prototype")
public AgentType1 agentType1(POJO agentPojo) {
return new AgentType1(agentPojo);
}
#Bean
#Scope("prototype")
public AgentType2 agentType2(POJO agentPojo) {
return new AgentType2(agentPojo);
}
}
In this case, I removed the #AgentAnnotation from the baseAgent class as we are now instantiating through this config. Also removed the ComponentScan line from the main App.
This time around, the #Autowired doesn't work. All Autowired references in the baseAgent class are null.
Please advise on the best approach to solve this error. Thanks.
Found the issue and solution.
Basically, I was expecting child classes to inherit #Component and #Scope, which it doesn't.
So essentially, I need to annotate each child class with #Component and #Scope("prototype").
The other problem was that I was expecting Autowired items in the constructor, which was too early. Adding a #PostConstruct addressed that issue.
So I ended up deleting the custom annotation and the configuration class and making the changes I just described.

Multi-tiered Spring application dependency resolution

I am trying to create a three-tier application with Spring, view, logic, data, more or less. The view depends on logic which depends on data.
How can I configure the Spring application in the view project such that the dependency graph is able to be resolved?
For example:
In the view layer:
#Controller
public class SomeView {
private final SomeService someService;
#Autowired
public SomeView(SomeService someService) {
this.someService = someService;
}
}
#Configuration
#EnableAutoConfiguration
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
In the logic layer:
#Component
public class SomeService {
private final SomeData someData;
#Autowired
public SomeService(SomeData someData){
this.someData = someData;
}
}
In the data layer:
#Component
public class SomeData {
}
This configuration is not able to boot because SomeService can't resolve SomeData because SomeData is not scanned in the view layers Application.java
when using #SpringBootApplication Spring boot uses default values. If you take a look at the #SpringBootApplication definition you will see that :
Many Spring Boot developers always have their main class annotated with #Configuration, #EnableAutoConfiguration and #ComponentScan. Since these annotations are so frequently used together (especially if you follow the best practices above), Spring Boot provides a convenient #SpringBootApplication alternative.
The #SpringBootApplication annotation is equivalent to using #Configuration, #EnableAutoConfiguration and #ComponentScan with their default attributes: [...]
That means :
#SpringBootApplication // same as #Configuration #EnableAutoConfiguration #ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Also, it means that when using default values for #ComponentScan your packages sturctures shloud be as following :
com.example.model -> your entities
com.example.repositoriy -> your repositories
com.example.controller -> controllers
com.example -> MainApplication class
If not following this structure you should tell to the #ComponentScan the package where to find the components :
Example 1:
#Configuration
#EnableAutoConfiguration
#ComponentScan({"com.my.package.controller","com.my.package.domain"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Exemple 2 :
#Configuration
#EnableAutoConfiguration
#ComponentScan(basePackageClasses = {SomeService.class, SomeData.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Also, i advice you to check this guide on how to structuring your code in a Spring Boot Application.

Spring, JavaConfig, BeanDefinition and empty getBeanClassName

If Spring bean configured with JavaConfig, it BeanDefinition can not resolve BeanClassName, and return null.
Same with xml or annotation config work well.
What's the problem? How to fix?
Example code with trouble for Spring Boot, only add imports:
interface Foo {}
class FooImpl implements Foo {}
#ComponentScan
#EnableAutoConfiguration
#Configuration
public class App implements CommandLineRunner {
public static void main(String... args) {
SpringApplication.run(App.class, args);
}
#Bean(name = "foo")
Foo getFoo() { return new FooImpl(); }
#Autowired
private ConfigurableListableBeanFactory factory;
#Override
public void run(String... args) {
BeanDefinition definition = factory.getBeanDefinition("foo");
System.out.println(definition.getBeanClassName());
}
}
I've faced the same problem while watching a Spring workshop on the YouTube, which used XML-based configuration. Of course, my solution is not production ready and looks like a hack, but it solved my problem:
BeanDefinition beanDefinition;
AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) bd;
StandardMethodMetadata factoryMethodMetadata = (StandardMethodMetadata) annotatedBeanDefinition.getFactoryMethodMetadata();
Class<?> originalClass = factoryMethodMetadata.getIntrospectedMethod().getReturnType();
Edit 1
It turns out that if you define your bean outside of configuration class using stereotype annotation, everything would work fine:
#Configuration
#ComponentScan(value = "foo.bar")
public class Config {}
and
package foo.bar.model.impl
#Component
class FooImpl implements Foo {...}

Categories