I'm trying to use Brave Tracer Inside the non component class.
This code is working fine in main project, setting context and getting context both are printing. But when I generate jar file and import it to different project 2 and run it, Only Getting context is printing and getting null error.
I'm new to spring-boot
Initial problem was I wanted to Autowired Tracer to my non-component class, I google it to solve this problem, I got this result in google. If any one have any other solution for this kind of problem.
Open to suggestion
Thank you.
// Project 1
// This is the main code, Generated a Jar file
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext ctx;
#Override
public void setApplicationContext(ApplicationContext appContext) {
System.out.println("Setting context");
ctx = appContext;
}
public static ApplicationContext getApplicationContext() {
System.out.println("Getting context");
return ctx;
}
}
// Project 2
// imported project 1 jar file to this project
// Added jar file below main package
// for simplicity i have used this in main class which is component class
#SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
// using this lines in non-component class
ApplicationContext contextUtils = ApplicationContextUtils.getApplicationContext();
contextUtils.getApplicationName();
}
}
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "org.springframework.context.ApplicationContext.getApplicationName()" because "contextUtils" is null
at com.omniauth.omniauth.OmniAuthApplication.main(OmniAuthApplication.java:26)
You are getting the NullPointerException because the code in the other project is calling getApplicationContext before the ApplicationContextUtils has been loaded.
In fact, the ApplicationContextUtils component may not be loaded at all, as by default, Spring Boot only loads components that are in the same package (or subpackages) as the main class (the one annotated with #SpringBootApplication). If the other project uses different package names, ApplicationContextUtils is never loaded.
Related
I have a SpringBoot app that has been working fine:
#SpringBootApplication(exclude = { DataSourceAutoConfiguration.class },
scanBasePackageClasses = { IndexSyncController.class, IndexerService.class })
#ImportResource("classpath:/spring.xml")
public class AppLauncher {
public static void main(String[] args) {
SpringApplication.run(AppLauncher.class, args);
}
And also currently sitting in src/test/java, I have a "utility" which has its own main method. This too has been working fine, but can only launched in my development environment:
#SpringBootApplication(exclude = { DataSourceAutoConfiguration.class,
WebMvcAutoConfiguration.class })
public class AuditApp {
public static void main(String[] args) {
SpringApplication.run(AppLauncher.class, args);
}
#Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
...
};
}
Now I have a new requirement
I need to take the AuditApp utility from src/test/java and make it available in the production jar.
So I just move it from src/test/java to src/main/java right? Nope! Very first obstacle I ran into when I do that, is that the main application tries to run the commandLineRunner(). Because of past experience with a similar requirement, I believe this is just the tip of the iceberg and there will be additional issues.
Is there a canonical, general best-practice or checklist for how to accomplish this?
The first thing to consider is the real reason of your problem.
You missed out packages of mentioned classes, but looking at your symptoms, I suspect your AuditApp is in the same package, or in a subpackage of one the AppLauncher is in (or is in package scanned by config declared inside imported spring.xml).
The #SpringBootApplication is an abbreviation for (amongst other) #SpringBootConfiguration and #ComponentScan.
Because of this the AppLauncher treats AuditApp as a #SpringBootConfiguration on a package scan and instantiates beans created within this config. The AuditApp.main method is never called, but the beans declared in the config are instantianted.
Let's say you have AppLauncher in com.yourapp and AuditApp in com.yourapp.audit.
If you move your utility application to the package which is not under the package scan for AppLauncher, like com.yourauditapp. The CommandLineRunner bean won't be created when running the original application. And the AuditApp won't affect the original application.
The only other way it can interfere is when it introduces dependencies which may trigger some Spring-Boot autoconfigurations.
I am creating a plugin for Minecraft server in which I use this SpringFramework. And I use JavaConfig + Annotations, but my project couldn't normally in runtime due to #ComponentScan.I discovered the fact that this is only in the Minecraft server plugin, but I could be wrong. Although in a normal Spring project everything is scanned normally
I have a directory like this: me.stordshally.testplugin
Main class (me.stordshally.testplugin.Main)
public class Main extends JavaPlugin {
private User user;
#Override
public void onEnable() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
user = context.getBean(FacebookUser.class);
}
}
JavaConfig (me.stordshally.testplugin.SpringConfig)
#Configuration
#ComponentScan
public class SpringConfig {
}
Component (me.stordshally.testplugin.FacebookUser) (exists also User interafce in that directory)
#Component
public class FacebookUser implements User {
#Override
public String getNet() {
return "Facebook";
}
}
And at the moment context.getBean I get this exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'me.stordshally.testplugin.FacebookUser' available
onEnable - starts when the server starts, consider it as an analog of psvm.
Why is this happening? How can I fix my ComponentScan?
Github for test: https://github.com/Prot-CN/SpringBug
Ideally, some more information would have helped, however, I do not know what the src package structure looks like but try explicitly providing base package like
#ComponentScan(basePackages = "me.stordshally.testplugin")
This tells spring explicitly where to look for potentials beans to create. Please make sure you provide the path under which all your beans are located.
If this doesn't work, it means for some reason your application is failing, try running your app in debug mode by setting log-level to debug. It will tell where the issue is. it's the best I can tell from the info provided, Hope this helps.
I have two projects A and B. I'm adding B as a pom dependecy of A.
My project A is a springboot application that has a Application.java class which implements ApplicationContextAware
Project B also has a App.java class that implements the ApplicationContextAware. In both I add the ApplicationContext to a static variable context
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
When I start A, and try to get a Bean of A from B using the context like :
Class<?> klass = Class.forName(klassName);
Myclass myclass = (MyClass) App.context.getBean(klass)
Application B has a class 1 that has a method init() that basically instantiates another class 2 with some external config parameters. The problem happens in the constructor of the class 2 where I try to create the bean for Myclass.
I get NoSuchBeanDefinitionException : No qualifying bean of type Myclass, However if I check(debugging) for App.context.classLoader() I can see my class defined there.
Another weird behaviour is that if I try to see Application.context from this debugging breakpoint, the context is null. This same static context is not null when I access this same attribute from the classes of project A.
I tested to add B to project A as an folder(copying everything) instead of using it as a jar. This made it work! So I think I have some problem with spring contexts here. But I really don't know what else to do.
Any suggestions would help,
Thanks!
I have a SpringBoot Application that works with another external JAR. When I try to #Autowired classes from the JAR , the SpringApp fails to load. I got "org.springframework.beans.factory.NoSuchBeanDefinitionException". I know this has to do with SpringBoot not searching where the project classes are, but I can't figure out how to correctly tell where to look. I've added #ComponentScan, it worked with other internal classes, but not with this External JAR.
This is the class where I use the JAR methods:
package ar.com.tr.latam.care.ws.service.impl;
#Configuration
#ComponentScan({
"ar.com.tr.arz.expurgo", "ar.com.tr.arz.expurgo.logger", "ar.com.tr.arz.expurgo.logger.dao", "ar.com.tr.arz.expurgo.logger.impl","ar.com.tr.arz.expurgo.logger.model"})
#Import({ AppConfig.class, AplicacionCriteriosExpurgoServiceImpl.class, ClasificacionServiceImpl.class, ExcelReaderServiceImpl.class, ConversionServiceImpl.class})
#Service
public class ArzServiceImpl implements ArzService {
#Autowired
private ExcelReaderService excelReaderService;
#Autowired
private ConversionService conversionService;
#Autowired
private AppConfig appConfig;
...
}
And my Init.java class:
package ar.com.tr.latam.care;
#Configuration
#ComponentScan({ "ar.com.tr.latam.care.controller",
"ar.com.tr.latam.care.filtro", "ar.com.tr.latam.care",
"ar.com.tr.latam.care.model.log", "ar.com.tr.latam.care.logger.impl", })
#EnableJpaRepositories
#SpringBootApplication
public class Init extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Init.class);
}
/**
* Main method.
*
* #param args String[].
* #throws Exception Exception.
*/
public static void main(String[] args) throws Exception {
SpringApplication.run(Init.class, args);
}
}
The JAR structure starts with "ar.com.tr.arz.expurgo" , but I can't find how to properly tell Springboot to check for those files there.
The error is "Could not autowire field: private ar.com.tr.arz.expurgo.services.ClasificacionService"
I've also tried adding the external JAR classes in the #ComponentScan Init class, but it also didn't work.
Any suggestions?
I was able to solve it.
First I remove the #ComponentScan from the #Service, and only called it in my Init.java class (Start of the application)
THen I changed my Init packagein order to be on an upper level of the jar classes :
My Init.java was under package ar.com.tr.latam.care, the External JAR package classes were under: package ar.com.tr.expurgo. So, I changed my Init.java to be in package ar.com.tr, and every worked!
I have already a webapp which is having Spring application context defined in a web.xml. Also I have a stand alone program in the same Project which call a webservice and get a list of products and insert those values in a table. This Stand alone program is like a scheduler which executes in its particular time.
My doubts are as follows.
Can I create an application context in my Stand alone program as below
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("/myConfig.xml");
or
How to get the already loaded application context in my web app.
can we have multiple application context created in a same project
1.Can I create an application context in my Stand alone program as below
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/myConfig.xml");
Yes, but make sure you do it only one.
2.can we have multiple application context created in a same project
yes, but it is not a good practise. So create ApplicationContext only once for you stand alone program (may be one for your web-application) and call the ApplicationContextProvider to get the existing ApplicationContext
The sample code to create the ApplicationContextProvider is given below with explanation.
Spring configuration
<bean id="applicationContextProvider" class="dell.harmony.service.ApplicationContextProvider"></bean>
This will be invoked by spring container, when it first creates an applicationcontext and the applicationContext will be passed to the setter method (setApplicationContext) . we expose the application context by the getApplicationContext() so that other methods can use it.
package dell.harmony.service;
import org.apache.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/*
*
* Utility Class to return the Spring ApplicationContext
*
*
*/
public class ApplicationContextProvider implements ApplicationContextAware {
private static Logger logger = Logger.getLogger(ApplicationContextProvider.class);
private static ApplicationContext ctx;
#Override
public void setApplicationContext(ApplicationContext arg0)
throws BeansException {
if (arg0 != null) {
ctx=arg0;
}
}
public synchronized static ApplicationContext getApplicationContext(){
if (ctx==null) {
logger.info("Getting the context again as it is null");
ctx = new ClassPathXmlApplicationContext("SpringModule.xml");
}
return ctx;
}
}
When ever you need the application context, use it as follows
First Time when scheduler is initialized.
logger.info("Spring Application Context !!");
ApplicationContext context = new ClassPathXmlApplicationContext("/SpringModule.xml");
logger.info("Spring Application Context - End !!");
In all other places, use as follows:
ApplicationContext context = ApplicationContextProvider.getApplicationContext();
SingleDataLoader dl = (SingleDataLoader) context.getBean("singledataloaderdao");
As you said you can create your context by loading the file
ApplicationContext context = null;
try {
context = new ClassPathXmlApplicationContext("classpath:config"+System.getProperty("file.separator")+"applicationContext.xml");
} catch (Throwable e){
logger.warn(e.getMessage());
logger.trace(e.getMessage(), e);
}
Please note that the classpath: refears to your /src directory in case of stand alone program (while for webapp is your docroot).
You can have how many application context you want, and you can configure spring to load witch ones you need in your web.xml (or in your Main.class)