Are there anyway to disable annotation in spring4? - java

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 {
}

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());
}
}

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.

Component scan using custom annotation

I am consuming a spring boot project as jar inside another spring boot application using the maven dependency. I want to do the component scan of jar only if I enable a custom annotation from microservice.
#SpringBootApplication
//#ComponentScan({"com.jwt.security.*"}) To be removed by custom annotation
#MyCustomAnnotation //If I provide this annotation then the security configuration of the jar should be enabled.
public class MicroserviceApplication1 {
public static void main(String[] args) throws Exception {
SpringApplication.run(MicroserviceApplication1.class, args);
}
}
Please suggest some ideas.
In your library:
#Configuration
#ComponentScan(basePackages = { "com.jwt.security" })
public class MyCustomLibConfig{
}
#Retention(RUNTIME)
#Target(TYPE)
#Import(MyCustomLibConfig.class)
public #interface MyCustomAnnotation{
#AliasFor(annotation = Import.class, attribute = "value")
Class<?>[] value() default { MyCustomLibConfig.class };
}
So, in your application you can use the annotation
#SpringBootApplication
#MyCustomAnnotation //If I provide this annotation then the security configuration
of the jar should be enabled.
public class MicroserviceApplication1 {
public static void main(String[] args) throws Exception {
SpringApplication.run(MicroserviceApplication1.class, args);
}
}
You can use #Conditional to define configurations (see an example describe here). Some code from the source
#Configuration
public class MyConfiguration {
#Bean(name="emailerService")
#Conditional(WindowsCondition.class)
public EmailService windowsEmailerService(){
return new WindowsEmailService();
}
#Bean(name="emailerService")
#Conditional(LinuxCondition.class)
public EmailService linuxEmailerService(){
return new LinuxEmailService();
}
}
and conditional
public class WindowsCondition implements Condition{
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("os.name").contains("Windows");
}
}
You can use profiles. Just add the #Profile to your config class with scan of desired package.
One more alternative is described here.
#AutoconfigureAfter(B.class)
#ConditionalOnBean(B.class)
public class A123AutoConfiguration { ...}

#EnableAspectJAutoProxy does not work

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>

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.

Categories