Spring boot Static inner class not initialised when application starts as a jar - spring

When I start up the my spring boot application via intellij, the following class initialised properly and the log can be seen. but if I run agains the jar from the build, MyCurrentTraceContext seem not initialised and I can't see the log in the output either. I do need this class with my customised logic to run put of some argument into MDC. Any advice?
#Configuration
#ConditionalOnProperty(value="spring.sleuth.enabled", matchIfMissing=true)
#AutoConfigureBefore(TraceAutoConfiguration.class)
public class MyLogConfiguration extends SleuthLogAutoConfiguration {
private static final Logger LOGGER = (Logger) LoggerFactory.getLogger(WtrLogConfiguration.class);
#Configuration
#ConditionalOnClass(MDC.class)
#EnableConfigurationProperties(SleuthSlf4jProperties.class)
protected static class MySlf4jConfiguration extends Slf4jConfiguration {
#Bean
#ConditionalOnProperty(value = "spring.sleuth.log.slf4j.enabled", matchIfMissing = true)
#ConditionalOnMissingBean
#Override
public CurrentTraceContext slf4jSpanLogger() {
LOGGER.info("************ OVER WRITTING WTIH WtrCurrentTraceContext*******");
return new MyCurrentTraceContext(Slf4jCurrentTraceContext.create());
}
}
}

Please check with
#ComponentScan
in top of your starter class to set the path you need to be scanned while project starts.
In your case that would be :
#ComponentScan("myPackagePath.MyLogConfiguration.MySlf4jConfiguration.*")

Related

where does spring boot set proxy as CGLib [duplicate]

Recently i found spring documentation page that says:
Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice).
If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used.
But it doesn't seem to be the case in my application. I wanted to write a small benchmark to compare the performance of both types of proxying.
There are two similar classes. Both have one method annotated with the #Transactional annotation. One class implements the interface and the other does not:
#Service
public class Cglib {
#Transactional
public void method() {}
}
public interface Dynamic {
void method();
}
#Service
public class DynamicImpl implements Dynamic {
#Override
#Transactional
public void method() {}
}
And based on the documentation for the first class, a CGLIB proxy should be created, and for the second, a JDK dynamic proxy.
But in my case CGLIB was used for both classes:
#Component
#RequiredArgsConstructor
public class Runner implements ApplicationRunner {
private final Cglib cglib;
private final Dynamic dynamic;
#Override
public void run(ApplicationArguments args) {
System.out.println(cglib.getClass());
System.out.println(dynamic.getClass());
}
}
class com.example.demo.proxy.cglib.Cglib$$EnhancerBySpringCGLIB$$767ff22
class com.example.demo.proxy.dynamic.DynamicImpl$$EnhancerBySpringCGLIB$$20a564d6
There are no additional configurations in the application. Only #SpringBootApplication class generated via spring initializr
Am I doing something wrong? The code was run on Spring Boot 2.7.2 and JDK 17.
That is due to spring-boot autoconfiguation:
#Configuration(proxyBeanMethods = false)
#ConditionalOnBean(TransactionManager.class)
#ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
public static class EnableTransactionManagementConfiguration {
#Configuration(proxyBeanMethods = false)
#EnableTransactionManagement(proxyTargetClass = false)
#ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
public static class JdkDynamicAutoProxyConfiguration {
}
#Configuration(proxyBeanMethods = false)
#EnableTransactionManagement(proxyTargetClass = true)
#ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}
it turns #EnableTransactionManagement(proxyTargetClass = true) (Indicate whether subclass-based (CGLIB) proxies are to be created (true) as opposed to standard Java interface-based proxies (false)) when the property spring.aop.proxy-target-class is not set (matchIfMissing = true)

SpringBoot Autowired only works with embedded Tomcat

I have a Spring Boot / Vaadin 14 application that is really causing me to scratch my head. I've done this a thousand times but cannot seem to find what I am missing.
When I run the app with the embedded Tomcat (spring-boot:run), everything works. But when I run it using an external Tomcat 9 (on my same machine), my autowired dependencies are null.
My code:
AppConfig.java
#SpringBootConfiguration
#ComponentScan("com.example.myapp")
#EnableVaadin
public class AppConfig implements Serializable {
private static final long serialVersionUID = -2113829779705972298L;
}
Vaadin ETL View:
#Route(value = "etl", layout = MainView.class)
#PageTitle("ETL")
#RouteAlias(value = "", layout = MainView.class)
public class EtlView extends Div implements Serializable {
private static final long serialVersionUID = -6417032793665450391L;
#Autowired
private AsyncRestClientService service; // this works with embedded. NULL with external.
...
AsyncRestClientService:
#Service
public class AsyncRestClientService implements Serializable {
...
MyApplication:
#SpringBootApplication
public class MyAppApplication {
public static void main(String[] args) {
SpringApplication.run(MyAppApplication .class, args);
}
}
All classes are in the com.example.myapp package so the component scan should pick this up.
Any ideas what I am missing?
BTW, I am doing the exact same thing with a Vaadin 8 application and everything works. Even with my external Tomcat 9.
Thanks
EDIT
Note, I am packaging this as a WAR in my pom.xml.
You probably need to package the app as a WAR instead of JAR when deploying a Spring Boot app to an external Tomcat. Check this out: https://spring.io/guides/gs/convert-jar-to-war

Spring #ConfigurationProperties not populated

I am experiencing problems using the #ConfigurationProperties feature.
Probably, I am missing something, since the mechanism seems very simple, but for me, it does not work.
I am using Spring Boot with the following main Application class
#SpringBootApplication
#EnableAspectJAutoProxy
#EnableConfigurationProperties(QueuesProperties.class)
#PropertySource("file:config/queues.properties")
#ImportResource("classpath:/spring-config.xml")
public class Application {
public static void main(String... args) {
ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
with QueuesProperties
#ConfigurationProperties(prefix = "wmq.in.queue")
public class QueuesProperties {
private static final Logger LOGGER = LoggerFactory.getLogger(QueuesProperties.class);
private String descr;
public String getDescr() {
return descr;
}
public void setDescr(String descr) {
this.descr = descr;
}
}
The properties file is very simple (I am trying to isolate the problem)
wmq.in.queue.descr = description
Then, I am trying to #Autowired the QueuesProperties in a #Component that I use in a spring-integration flow with a .
The QueuesProperties is correctly injected but the descr attribute is null.
#Autowired
private QueuesProperties queuesConfiguration;
while this
#Value("${wmq.in.queue.descr}")
private String descr;
is correctly evaluated.
I have made a lot of attempt with different configurations or code, but the result is the same. I get the QueuesProperties bean but it is not populated.
What am I missing?
Reading the question isn't very clear if the wmq.in.queue.descr = description properties is written in applciation.properties file. I said it because you say that the properties is correctly evaluated with #Value and not with
#Autowired
private QueuesProperties queuesConfiguration;
Even the #PropertySource("file:config/queues.properties") let me to think that probably the your wmq.in.queue.descr = description properties isn't written in applciation.properties but in file:config/queues.properties.
Summing
For use #ConfigurationProperties feature you have write the properties in application.properties and use #EnableConfigurationProperties(QueuesProperties.class) on #Component, #Configuration and so on annotated classes like below.
#Component
#EnableConfigurationProperties(QueuesProperties.class)
public class YourBean {
....
private final QueuesProperties queuesProperties;
public YourBean(QueuesProperties queuesProperties){
this.queuesProperties = queuesProperties;
}
.....
}
actually you can change the application.properties file name customizing spring boot properties evaluation but for your local app I discourage. I consider application.properties a good name for naming a place in which you put the configuration properties of your application
I hope that it can help you

Execute CommandLineRunner outside #SpringBootApplication

This is based on https://spring.io/guides/gs/accessing-data-jpa/
I tried to move demo() in a different class in a different package (Application still on top of the filesystem hierarchy)
How do I make demo() run when i boot the project?
Application.java
package com.company.app
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
CommandLineRunner.java
package com.company.app.runner
public class Test {
#Bean
public CommandLineRunner demo() {
System.out.print("Run 1");
return (args) -> {
System.out.print("Run 2");
};
}
}
Add #Configuration to the Test class so that it is picked up when the classpath is scanned.
I haven't seen a Lambda for the CommandLineRunner before. Very nifty and saves having to create a class that specifically implements the CommandLineRunner.
Otherwise, you could implement CommandLineRunner to test and annotate as #Component.
#Component
public class ApplicationLoader implements CommandLineRunner {
#Override
public void run(String... strings) throws Exception {
System.out.print("Run 2");
}
}
* Update *
Answering the question in the comment with this update as I have more room to type...
#SpringBootApplication composes those other annotations as you indicated but those annotations are only applied to the specific class that it is defined on. The #Configuration annotation is telling Spring that the class defines beans that should be managed by the application context. The #ComponentScan tells spring to look through the classpath for classes that have specific annotations (e.g. #Component, #Service, #Configuration) and then act on those classes based on the type of annotation. the #EnableAutoConfiguration is the magic that loads appropriate beans based on the project dependencies (e.g. if mongo driver is on the classpath then create a MongoTemplate).

Spring automagic, #Autowired

#Autowired
Environment env;
#Value("${jdbcConnectionString}")
private String jdbcConnectionString;
The above works automagically in certain classes, however is null in similar classes in same package and with same annotations #Configuration/#Component.
I am trying to find out the proper approach to understand what spring does when while configuring various artifacts.
I am able to run stuff every now and then but any good resource to understand the magic is well appreciated.
PS. I am only interested in java-config based approach now.
Working :
package a.b.c;
#Configuration
public class AppConfig {
#Autowired
Environment env;
package a.b.d;
#Configuration
#EnableBatchProcessing
public class JobConfiguration {
#Autowired
private Environment env;
package a.b.L;
public class BatchJobListener implements Ordered, JobExecutionListener {
#Autowired
public Environment env;
Not working inside
package a.b.u
Tried to annotate classes with #Component/#Configuration
In order to autowire a bean, you need first to defined it in a Context.
#Configuration
public class ConfigOne {
#Bean
public String myBean(){
return "my bean";
}
}
The bean that you want to inject and the bean where the bean will be injected need to be in the same context. You can do it with:
JavaConfigApplicationContext context =
new JavaConfigApplicationContext(ConfigOne.class, ConfigTwo.class);
Or you can use #import to import one configuration class into another.
#Configuration
#Import(ConfigTwo.class)
public class ConfigOne {
UPDATE
What I meant was that probably you're not making the configuration in the ringht way. So all your beans where you're injecting the enviroment are not in the same context.
However, if you have configured well everything, it's possible that some classes are loading before enviroment. In this case you can use EnvironmentAware
#Configuration
#PropertySource("classpath:myProperties.properties")
public class MyConfiguration implements EnvironmentAware {
private Environment environment;
#Override
public void setEnvironment(final Environment environment) {
this.environment = environment;
}
public void myMethod() {
final String myPropertyValue = environment.getProperty("myProperty");
// ...
}
}
In your main class where you are initializing the spring boot application, do you have similar configuration:
#Configuration
#SpringBootApplication
#EnableAutoConfiguration
#ComponentScan("a.b") //Note that this scans the components where you have configured spring container backed objects
#PropertySource({
"classpath:someProperty1.properties",
"classpath:someProperty2.properties"
})
public class Main{
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
What this basically does is, it tells spring that this is a configuration class, and indicates this configuration class that it also triggers auto-configuration and component scanning (scan only these specific packages (a.b) and check if there are any annotations present for automatic bean detection, like: #Component, #Service, #Controller, #Repository). On detecting any class which have these stereotypes spring would create object(s) depending on the configuration. On creating these objects one may have autowired some objects or one could refer to some property defined in properties file. The config #PropertySource does this.
The package declaration in #ComponentScan should be the base package.

Resources