I build a web project with spring boot 1.5.4
And create a class implements ApplicationContextAware
#Component
public class SpringContextUtils implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtils.context = context;
}
public static ApplicationContext getContext() {
return context;
}
Then I create a controller to test this class
#Controller
public class TestController {
#RequestMapping(value = "test", method = RequestMethod.GET)
public #ResponseBody String test(){
System.out.println(SpringContextUtils.getContext());));
return "aaa";
}
}
than I start the application
#SpringBootApplication
#ServletComponentScan
#EnableTransactionManagement
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I visited this controller but SpringContextUtils.getContext() out put null,why?
I am sure SpringContextUtils scaned by spring.
I know I can use #Autowired to get ApplicationContext,but I want to know why my program is wrong and how can I get it with ApplicationContextAware
Related
I have Controllers, Services and DAOs in separate spring boot modules. I tried calling a stored procedure from DAO module using JPA API StoredProcedureQuery method, for that I need to autowire EntityManager. This set up works if I run DAO alone as a spring boot application. But I am getting NullPointerException when I call this DAO class from controller.
My LoginDAO in DAO project
#Repository
public class LoginDAO implements ILoginDAO {
#Autowired
EntityManager entityManager;
#Transactional
public LoginEntity getLoginCheck(String[] loginfo) {
StoredProcedureQuery storedProcedure =entityManager.createStoredProcedureQuery("DPR_LOGIN_CHECK");
}
}
My LoginController class in Controller Module
#Controller
public class LoginController {
#Autowired
LoginDAO loginDAO;
#RequestMapping(value = "/LoginAction", method = RequestMethod.POST)
public #ResponseBody
String getLoginCheck(#RequestParam(value = "dataString") String dataString,
HttpSession session, HttpServletRequest request,
HttpServletResponse response) {
loginDAO.getLoginCheck(null,loginDetails);
}
}
My controller project is dependent on DAO. Here is my main controller class
#SpringBootApplication(scanBasePackages={"com.mars.presentation","com.mars.UserManagementControllers","com.mars","com.mars.CommonDAO"})
public class MarsApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MarsApplication.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(MarsApplication.class, args);
}
}
and main DAO class
#SpringBootApplication(scanBasePackages={"com.mars.CommonDAO"})
#EntityScan(basePackages={"com.mars.CommonEntities"})
#EnableJpaRepositories
public class CommonDao {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(CommonDao.class, args);
String[] loginfo = new String[] {"cjva", "Banaacvdvna", "Orange", "Grapes"};
LoginDAO loginDAO = ctx.getBean(LoginDAO.class);
loginDAO.getLoginCheck(null,loginfo);
}
}
I have following repository which extends jpa repositroy and also have an implementation class where i have autowired this.
#Repository
public interface ProjectDAO extends CrudRepository<Project, Integer> {}
#Service
public class ProjectServiceImpl {
#Autowired private ProjectDAO pDAO;
public void save(Project p) { pDAO.save(p); } }
Now i have one Application.java class
Class Application{
public static void main(String..s){
// I need a way to call a method of repository
}
}
configuration file
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories
#PropertySource("file:/Users/abc/Documents/application.properties")
public class PersistenceContext {
#Autowired
Environment environment;
So how do we call this from main in case i dont to use any web based controller?
This is a way:
class Application {
public static void main(String[] s){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(PersistenceContext.class);
ProjectDAO dao = applicationContext.getBean(ProjectDAO.class);
}
}
Edit:
class Application {
public static void main(String[] s){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(PersistenceContext.class);
ProjectServiceImpl service = applicationContext.getBean(ProjectServiceImpl.class);
}
}
I am working on a Spring Boot application wherein I am using that application to expose a SOAP webservice. I am using Apache CFX framework for SOAP impl in Spring boot app. I am using Annotation based approach.
I am facing issue in setting the Application Context from the Spring Boot Configuration file in one of the Beans. Below is my code.
#SpringBootApplication
#ComponentScan("com.test")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The configuration file is as below.
#Configuration
public class WebServiceConfiguration {
//All individual bean definitions should go here
#Autowired
ApplicationContext appContext;
#Bean
public ServletRegistrationBean cxfServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/soap-api/*");
}
#Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
#Bean(name="IValidator")
public IValidator getValidator(){
return new Validator();
}
#Bean(name="SOAPprocessImpl")
public IPSoap getService() {
return new SOAPprocessImpl();
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), getService());
endpoint.publish("/WS_1.0");
endpoint.setWsdlLocation("process.wsdl");
return endpoint;
}
Now I have the bean SOAPprocessImpl implementation in which I need to get the Application Context so that I can get handle to the Validator bean. I have declared SOAPprocessImpl as a bean in the configuraton file. The code is as below
#javax.jws.WebService (endpointInterface="com.test.IPSoap")
public class SOAPprocessImpl implements IPSoap, ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ac)
throws BeansException {
context = ac;
}
private static final Logger logger = Logger.getLogger(SOAPprocessImpl.class.getName());
private IValidator validator = (IValidator) context.getBean("IValidator"); // context is NULL here
public IRResponse GetBalance(TSSearchParams SearchParams) {
// Some processing logic
}
}
So the issue is that when I run the boot application by deploying to the embedded Tomcat then the Application Context is not getting set in the SOAPprocessImpl class even after implementing the ApplicationContextAware. I also tried Autowiring but that also is not working.
Strangely I tried to see if I can get the ApplicationContext in the Configuration file where all the bean are defined. Here it is getting setting properly.
Can anyone help me how to solve this issue. I am new to Spring Boot and may have missed some configutaion. Thanks in advance.
Option(1): To fix the issue, you need to use #Configuration to register your SOAPprocessImpl bean to the Spring container as shown below so that ApplicationContext object can be injected :
#Configuration
#javax.jws.WebService (endpointInterface="com.test.IPSoap")
public class SOAPprocessImpl implements IPSoap, ApplicationContextAware {
private static ApplicationContext context;
private IValidator validator;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ac)
throws BeansException {
SOAPprocessImpl.context = ac;
}
#PostConstruct//use PostConstruct
public void init() {
validator = (IValidator) context.getBean("IValidator");
}
//add your current code
}
The important point is that you can't use the context object until the bean is prepared by the container, so you need to use #PostConstruct method as shown above to initialise your variables.
Option2 (recommended):
The best approach is that you can use #Autowired to inject IValidator object into SOAPprocessImpl as shown below so that you don't need your SOAPprocessImpl bean to be aware of ApplicationContextAware. Spring container will inject the instance for the implementation provided for the IValidator class (provided it is under the packages of #Componentscan).
#Component
#javax.jws.WebService (endpointInterface="com.test.IPSoap")
public class SOAPprocessImpl implements IPSoap {
private static final Logger logger = Logger.getLogger(SOAPprocessImpl.class.getName());
#Autowired //spring directly injects this object
private IValidator validator;
public IRResponse GetBalance(TSSearchParams SearchParams) {
// Some processing logic
}
}
I have defined a class MyFrontService in a jar, here is how I want to use it:
import blabla.MyFrontService;
public class Main {
public static void main(String[] args) {
MyFrontService.doThis();
}
}
The FrontService serves as an entry point to access other services.
Here is how it is currently defined (and it works).
MyFrontService.java:
public class MyFrontService {
public static void doThis(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/springBeans.xml");
MyService1 myService1 = (MyService1) context.getBean("myService1");
myService1.doSomething();
context.close();
}
}
MyService1.java:
package blabla.service;
#Service("myService1")
public class MyService1 {
public void doSomething(){
// some code
}
}
src/main/resources/META-INF/springBeans.xml:
(...)
<context:annotation-config />
<context:component-scan base-package="blabla.service" />
(...)
I would like to replace the code of MyFrontService.java by something like this:
#MagicAnnotation("what_path?/springBeans.xml")
public class MyFrontService {
#Autowired
private static MyService1 myService1;
public static void doThis(){
myService1.doSomething();
}
}
I've read a lot from other questions on this website and others. It is sometimes said that it's impossible, and sometimes annotations like #Configuration, #Import and others are used but I can't make them work. For example, using
#ImportResource("classpath:META-INF/springBeans.xml")
triggers a NullPointerException when calling myService1.doSomething().
If it is possible to do it, what annotation and what path should I use?
Use Spring Boot framework and you will be able to write smth like this
#Controller
#EnableAutoConfiguration
public class SampleController {
#RequestMapping("/")
#ResponseBody
String home() {
return "Hello World!";
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleController.class, args);
}
}
if you mark your class MyFrontService with #Component annotation that should save the headache of doing all the stuff you are doing. if you dont want to add the annotation and dont want to have everything under spring config you can define a class as below.
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
#Override
public void setApplicationContext(
org.springframework.context.ApplicationContext ctx)
throws BeansException {
applicationContext = ctx;
}
}
And then in any class you can do,
ApplicationContext ctx = SpringContextUtil.getApplicationContext();
BeanClass av = ctx.getBean(BeanClass.class);
I'm using annotation-configuration, not XML for my application...
#Configuration
#ComponentScan(basePackages = {
"com.production"
})
#PropertySource(value= {
"classpath:/application.properties",
"classpath:/environment-${COMPANY_ENVIRONMENT}.properties"
})
#EnableJpaRepositories("com.production.repository")
#EnableTransactionManagement
#EnableScheduling
public class Config {
#Value("${db.url}")
String PROPERTY_DATABASE_URL;
#Value("${db.user}")
String PROPERTY_DATABASE_USER;
#Value("${db.password}")
String PROPERTY_DATABASE_PASSWORD;
#Value("${persistenceUnit.default}")
String PROPERTY_DEFAULT_PERSISTENCE_UNIT;
In this file I've noticed I can obtain configuration values from the #PropertySource files. How can I obtain these values outside of a spring managed bean?
Is it possible for me to use my ApplicationContextProvider to obtain these values?
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext (ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
If I understand you correctly, yes you can use your ApplicationContextProvider class. #PropertySource properties end up in the ApplicationContext Environment. You can therefore access them like
public static class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext (ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
Environment env = applicationContext.getEnvironment();
System.out.println(env.getProperty("db.user")); // access them
}
}
So basically anywhere you have a reference to the ApplicationContext, you can get the properties declared in a #PropertySources or a PropertySourcesPlaceholderConfigurer.
However, in this case, the ApplicationContextProvider will have to be declared as a Spring bean in your context.
#Bean
public ApplicationContextProvider contextProvider() {
return new ApplicationContextProvider();
}