Environment properties not getting read in spring boot - java

I have a utility class to read the environment variables.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
#Component
public final class PropertyUtil {
/** The system environment. */
private static Environment environment;
public static String getConfigProp(final String key) {
return environment.getProperty(key);
}
#Autowired
public void setEnvironment(Environment environment) {
PropertyUtil.environment = environment;
}
}
And I use it in one bean while initialization. The problem is that it runs file if I deploy the war file on tomcat but if I run the same application as a spring boot application from eclipse, it does not read the environment properties and the return values are therefore null.
Any idea what could be the cause of this problem?

package com.myspringboot.controller;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
#Component
public class PropertyUtil implements EnvironmentAware {
/** The system environment. */
public Environment environment;
public String getConfigProp(String key) {
return environment.getProperty(key);
}
#Override
public void setEnvironment(Environment arg0) {
environment=arg0;
}
}
#Test
public void testProperty(){
/* String driver= System.getenv().get("spring.datasource.driverClassName");
System.out.println(driver);
System.out.println(PropertyUtil.environment);*/
String str= propertyUtil.getConfigProp("spring.datasource.driverClassName");
System.out.println(str);
}

package com.myspringboot.controller;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
#Component
public final class PropertyUtil implements EnvironmentAware {
/** The system environment. */
public static Environment environment;
public static String getConfigProp(String key) {
return environment.getProperty(key);
}
#Override
public void setEnvironment(Environment arg0) {
if(environment==null){
environment=arg0;
}
}
}

Related

OpenApi 3 codegen java how to implement

Have an openapi yml file with contains a simple get request with response, from this yml have the java files below been generated (among others).
How should these java files be used?
How to hook into the generated files?
Could simply copy the generated main and controller class into the main source tree, but does not seem to be the correct way.
--- edit ---
In the generated Controller class, how do I override the default responses that exist in the interface ExampleApi? Without having to modify the generated Controller class and have it in the VCS.
--- edit ---
build.gradle.kts
...
openApiGenerate {
generatorName.set("spring")
inputSpec.set("$rootDir/specs/api-example.yml")
outputDir.set("$buildDir/generated")
apiPackage.set("com.example.openapi.generated.api")
invokerPackage.set("com.example.openapi.generated.invoker")
modelPackage.set("com.example.openapi.generated.model")
configOptions.set(mapOf(
"dateLibrary" to "java8"
))
systemProperties.set(mapOf(
"modelDocs" to "false"
))
}
...
What should be done with these classes?
package com.example.openapi.generated.invoker;
import com.fasterxml.jackson.databind.Module;
import org.openapitools.jackson.nullable.JsonNullableModule;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#SpringBootApplication
#ComponentScan(basePackages = {"com.example.openapi.generated.invoker", "com.example.openapi.generated.api" , "org.openapitools.configuration"})
public class OpenAPI2SpringBoot implements CommandLineRunner {
#Override
public void run(String... arg0) throws Exception {
if (arg0.length > 0 && arg0[0].equals("exitcode")) {
throw new ExitException();
}
}
public static void main(String[] args) throws Exception {
new SpringApplication(OpenAPI2SpringBoot.class).run(args);
}
static class ExitException extends RuntimeException implements ExitCodeGenerator {
private static final long serialVersionUID = 1L;
#Override
public int getExitCode() {
return 10;
}
}
#Bean
public WebMvcConfigurer webConfigurer() {
return new WebMvcConfigurer() {
/*#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("Content-Type");
}*/
};
}
#Bean
public Module jsonNullableModule() {
return new JsonNullableModule();
}
}
package com.example.openapi.generated.api;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.NativeWebRequest;
import java.util.Optional;
#Controller
#RequestMapping("${openapi.basic.base-path:}")
public class ExampleApiController implements ExampleApi {
private final NativeWebRequest request;
#org.springframework.beans.factory.annotation.Autowired
public ExampleApiController(NativeWebRequest request) {
this.request = request;
}
#Override
public Optional<NativeWebRequest> getRequest() {
return Optional.ofNullable(request);
}
}
You need to tell gradle to compile the files, there is no need to copy them.
Add the path with the generated files to the sourceSets of your project. Something like this:
sourceSets {
main {
java {
srcDir("$buildDir/generated")
}
}
}

Secondary type dependency injection does not work in spring boot

As per the documentation, spring boot will automatically check the bean class object created in any classes annotated with #Configuration & will override the default bean of that class & return the object with any properties that are injected as it is defined. But when i test this application in junit, it does not return any value that is being injected. All my classes are defined in the same package My code is as below,
//Engine class
package com.test.simpletest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class Engine {
private String msg;
public Engine() {
System.out.println("Engine class is being called");
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
//Test configuration class
package com.test.simpletest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class TestConfiguration{
#Bean
public Engine engine() {
Engine eng = new Engine();
eng.setMsg("Message is being called");
return eng;
}
}
//Spring boot main app
package com.test.simpletest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class SimpleTestExampleApplication {
public static void main(String[] args) {
SpringApplication.run(SimpleTestExampleApplication.class, args);
}
}
//JUnit Test class
package com.test.simpletest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest
public class SimpleTestExampleApplicationTests {
#Autowired
private Engine engine;
#Test
public void contextLoads() {
engine.getMsg();
//Both above and below approach does not work
// ApplicationContext apx = new
AnnotationConfigApplicationContext(TestConfiguration.class);
// Engine engine = (Engine)apx.getBean(Engine.class);
// engine.getMsg();
}
}
Please help me in finding a solution to the above problem.
DemoApplication
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Engine
public class Engine {
private String msg;
public Engine() {
System.out.println("Engine class is being called");
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
TestConfiguration
#Configuration
public class TestConfiguration {
#Bean
public Engine getEngine() {
Engine eng = new Engine();
eng.setMsg("Message is being called");
return eng;
}
}
DemoApplicationTests
#RunWith(SpringRunner.class)
#SpringBootTest
#Import(TestConfiguration.class)
public class DemoApplicationTests {
#Autowired
private Engine engine;
#Test
public void contextLoads() {
System.out.println("engine : " + engine.getMsg());
}
}
Output
Engine class is being called
engine : Message is being called
Can you please remove #Component from Engine class and try again. I guess it’s should work fine.

Jersey HK2 Dependency Injection

I'm writing a simple microservices that exposes REST API. So I started working with Jersey and of course I need to Inject my object into jersey resources. Basically I have 2 classes that defines a set of resources and some of them need to use another service.
So basically I have:
public interface MyService {
String getServiceName();
void doService();
}
2 implementations of this interface (MyServiceBean and MyAlternativeServiceBean)
and, as far as I understood reading jersey docs, I defined an hk2 Binder:
public class MyBinder implements Binder{
#Override
public void bind(DynamicConfiguration config) {
DescriptorImpl descriptor = BuilderHelper.link(MyServiceBean.class).named("MyServiceBean").to(MyService.class).build();
config.bind(descriptor);
config.bind(BuilderHelper.link(MyAlternativeServiceBean.class).named("MyAlternativeServiceBean").to(MyService.class).build());
}
I registered this binder to the ApplicationConfig class
public class ApplicationConfig extends ResourceConfig{
public ApplicationConfig(){
property("property.value", "MyAlternativeServiceImplementation");
registerInstances(new MyBinder());
}
}
And annotated properly into the resources
#Path("first")
public class First {
#Inject #Named(value = "MyServiceBean")
private MyService myService;
//...
}
#Path("second")
public class Second {
#Inject #Named(value = "MyAlternativeServiceBean")
private MyService myService;
//...
}
All works until MyService implementation have no args constructor. But in 1 case I need to provide a dependency also to MyAlternativeServiceBean.
Here is the constructor
#Inject #Named("property.value")
public MyAlternativeServiceBean(String property){
this.property = property;
}
But I get an exception:
javax.servlet.ServletException: A MultiException has 5 exceptions. They are:|1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=String,parent=MyAlternativeServiceBean,qualifiers={}),position=0,optional=false,self=false,unqualified=null,2080509613)|2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.hpe.services.MyAlternativeServiceBean errors were found|3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.hpe.services.MyAlternativeServiceBean|4. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.hpe.tests.SecondEntryPoint errors were found|5. java.lang.IllegalStateException: Unable to perform operation: resolve on com.hpe.tests.SecondEntryPoint|
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:392)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:381)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:344)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:219)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:501)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:229)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:427)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
at org.eclipse.jetty.server.Server.handle(Server.java:370)
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:494)
at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:973)
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:1035)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:641)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:231)
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:696)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:53)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
at java.lang.Thread.run(Thread.java:745)
Basically I don't konw how to inject properties/constants (that I can read from a configuration file for instance) in hk2
Thanks
Regards
What you can do is create a custom annotation
#Target({ElementType.FIELD, ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
public #interface Config {
String value();
}
Then create an InjectionResolver for it (which allows for injection using custom annotations)
public static class ConfigInjectionResolver implements InjectionResolver<Config> {
private static final Map<String, String> properties = new HashMap<>();
public ConfigInjectionResolver() {
properties.put("greeting.message", "Hello World");
}
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
if (String.class == injectee.getRequiredType()) {
AnnotatedElement elem = injectee.getParent();
if (elem instanceof Constructor) {
Constructor ctor = (Constructor) elem;
Config config = (Config) ctor.getParameterAnnotations()[injectee.getPosition()][0];
return properties.get(config.value());
} else {
Config config = elem.getAnnotation(Config.class);
return properties.get(config.value());
}
}
return null;
}
#Override
public boolean isConstructorParameterIndicator() { return true; }
#Override
public boolean isMethodParameterIndicator() { return false; }
}
This example just uses a Map, but I'm sure you can figure out how to make it use Properties. Once you register the InjectionResolver, you can now just do
public SomeService(#Config("some.property") String property) {}
Here is a complete test case
import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import java.lang.annotation.*;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import static org.junit.Assert.*;
/**
* Run like any other JUnit Test. Only one required dependency
*
* <dependency>
* <groupId>org.glassfish.jersey.test-framework.providers</groupId>
* <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
* <version>${jersey2.version}</version>
* </dependency>
*
* #author Paul Samsotha
*/
public class ConfigExample extends JerseyTest {
#Target({ElementType.FIELD, ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
public static #interface Config {
String value();
}
public static class ConfigInjectionResolver implements InjectionResolver<Config> {
private static final Map<String, String> properties = new HashMap<>();
public ConfigInjectionResolver() {
properties.put("greeting.message", "Hello World");
}
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
if (String.class == injectee.getRequiredType()) {
AnnotatedElement elem = injectee.getParent();
if (elem instanceof Constructor) {
Constructor ctor = (Constructor) elem;
Config config = (Config) ctor.getParameterAnnotations()[injectee.getPosition()][0];
return properties.get(config.value());
} else {
Config config = elem.getAnnotation(Config.class);
return properties.get(config.value());
}
}
return null;
}
#Override
public boolean isConstructorParameterIndicator() { return true; }
#Override
public boolean isMethodParameterIndicator() { return false; }
}
private static interface GreetingService {
String getGreeting();
}
private static class ConfiguredGreetingService implements GreetingService {
private String message;
public ConfiguredGreetingService(#Config("greeting.message") String message) {
this.message = message;
}
#Override
public String getGreeting() {
return this.message;
}
}
#Path("greeting")
public static class GreetingResource {
#Inject
private GreetingService greetingService;
#GET
public String getConfigProp() {
return greetingService.getGreeting();
}
}
#Override
public ResourceConfig configure() {
ResourceConfig config = new ResourceConfig(GreetingResource.class);
config.register(new LoggingFilter(Logger.getAnonymousLogger(), true));
config.register(new AbstractBinder(){
#Override
protected void configure() {
bind(ConfiguredGreetingService.class).to(GreetingService.class).in(Singleton.class);
bind(ConfigInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<Config>>(){})
.in(Singleton.class);
}
});
return config;
}
#Test
public void should_get_configured_greeting() {
final Response response = target("greeting")
.request().get();
assertEquals("Hello World", response.readEntity(String.class));
}
}

Start thread at springboot application

I want to execute a java class (which contains a java thread I want to execute) after spring boot starts. My initial code:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And here is is the code I want to execute at start:
public class SimularProfesor implements Runnable{
// Class atributes
// Constructor
public SimularProfesor() {
//Initialization of atributes
}
#Override
public void run() {
while(true) {
// Do something
}
}
}
How can I call this thread? This is what I'm supposed to do:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
// Call thread (constructor must be executed too)
}
}
Don't mess around with threads yourself. Spring (and also plain Java) has a nice abstraction for that.
First create a bean of the type TaskExecutor in your configuration
#Bean
public TaskExecutor taskExecutor() {
return new SimpleAsyncTaskExecutor(); // Or use another one of your liking
}
Then create a CommandLineRunner (although an ApplicationListener<ContextRefreshedEvent> would also work) to schedule your task.
#Bean
public CommandLineRunner schedulingRunner(TaskExecutor executor) {
return new CommandLineRunner() {
public void run(String... args) throws Exception {
executor.execute(new SimularProfesor());
}
}
}
You could of course make also your own class managed by spring.
Advantage of this is that Spring will also cleanup the threads for you and you don't have to think about it yourself. I used a CommandLineRunner here because that will execute after all beans have bean initialized.
Main Class SpringBoot
#SpringBootApplication
#EnableAsync
#Controller
public class ...
Example Class Controler
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
#Component
public class ExecutorBase {
private static final Logger log = LoggerFactory.getLogger(ExecutorBase.class);
#Autowired
private TaskExecutor taskExecutor;
#Autowired
private ApplicationContext applicationContext;
private Boolean debug = true;
#PostConstruct
public void atStartup() {
ClasseTaskRunn classeTaskRunn = applicationContext.getBean(ClasseTaskRunn.class);
taskExecutor.execute(classeTaskRunn );
if (debug) {
log.warn("###### Startup ok");
}
}
}
Example Class Task Runnable
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
#Component
#Scope("application")
public class ClasseTaskRunn implements Runnable {
private static final Logger log = LoggerFactory.getLogger(ClasseTaskRunn.class);
#Autowired
ClasseDAO classeDAO;
#Override
public void run() {
longBackgorund();
}
protected void longBackgorund() {
while (test) {
if (debug) {
log.warn("###### DEBUG: " ... );
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

Spring cacheManager is not singleton?

I have some problems with an spring AnnotationConfigApplicationContext.
The main aim is to create a Spring Configuration which can be run on application server or standalone. Subtask to make subcontext from this one which will be used by another application on the same AppServer.
But have some trouble with cacheManager.
That's my code:
aka AbstractConfig
package org.zib.test.a;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
#Configuration
#EnableCaching
public class ConfigA {
#SuppressWarnings("UnusedDeclaration")
public static ApplicationContext getContext() {
return ContextA.getInstance().getContext();
}
/**
* use {#link org.zib.test.b.ContextB}
*/
public static <T> T getBean(Class<T> bean) {
return ContextB.getInstance().getContext().getBean(bean);
}
/**
* use {#link ContextB}
*/
public static <T> T getBean(String name, Class<T> bean) {
return ContextB.getInstance().getContext().getBean(name, bean);
}
#Bean(name = "cacheManager")
public CacheManager cacheManager() {
// configure and return an implementation of Spring's CacheManager SPI
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("default")));
return cacheManager;
}
}
aka AbstractContext
package org.zib.test.a;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ContextA {
private ApplicationContext applicationContext;
public static ContextA instance;
public static ContextA getInstance() {
synchronized (ContextA.class) {
if (instance == null)
instance = new ContextA();
}
return instance;
}
private ContextA() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ConfigA.class);
applicationContext.registerShutdownHook();
applicationContext.refresh();
this.applicationContext = applicationContext;
}
public ApplicationContext getContext() {
return applicationContext;
}
}
Mode Config (for example, WebLogicConfig)
package org.zib.test.b;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;
import org.zib.test.a.ConfigA;
#Configuration
#EnableCaching
#Import(ConfigA.class)
public class ConfigB {
#SuppressWarnings("UnusedDeclaration")
public static ApplicationContext getContext() {
return ContextB.getInstance().getContext();
}
/**
* use {#link ContextB}
*/
public static <T> T getBean(Class<T> bean) {
return ContextB.getInstance().getContext().getBean(bean);
}
/**
* use {#link ContextB}
*/
public static <T> T getBean(String name, Class<T> bean) {
return ContextB.getInstance().getContext().getBean(name, bean);
}
}
context:
package org.zib.test.b;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.zib.test.a.ContextA;
public class ContextB {
private ApplicationContext applicationContext;
public static ContextB instance;
public static ContextB getInstance() {
synchronized (ContextB.class) {
if (instance == null)
instance = new ContextB();
}
return instance;
}
private ContextB() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ConfigB.class);
applicationContext.setParent(ContextA.getInstance().getContext());
applicationContext.registerShutdownHook();
applicationContext.refresh();
this.applicationContext = applicationContext;
}
public ApplicationContext getContext() {
return applicationContext;
}
}
And final - module config:
package org.zib.test.c;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
#Configuration
#EnableCaching
public class ConfigC {
#SuppressWarnings("UnusedDeclaration")
public static ApplicationContext getContext() {
return ContextC.getInstance().getContext();
}
/**
* use {#link ContextC}
*/
public static <T> T getBean(Class<T> bean) {
return ContextC.getInstance().getContext().getBean(bean);
}
/*DELTE BY SUGGESTION OF Tomasz Nurkiewicz
#Bean(name = "cacheManager")
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("default")));
return cacheManager;
}*/
}
and its context:
package org.zib.test.c;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.zib.test.a.ContextA;
import org.zib.test.b.ContextB;
public class ContextC {
private ApplicationContext applicationContext;
public static ContextC instance;
public static ContextC getInstance() {
synchronized (ContextC.class) {
if (instance == null)
instance = new ContextC();
}
return instance;
}
private ContextC() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ConfigC.class);
applicationContext.setParent(ContextA.getInstance().getContext());
applicationContext.registerShutdownHook();
applicationContext.refresh();
this.applicationContext = applicationContext;
}
public ApplicationContext getContext() {
return applicationContext;
}
}
My test class:
package org.zib.test;
import org.springframework.cache.CacheManager;
import org.zib.test.a.ConfigA;
import org.zib.test.c.ConfigC;
public class Test {
public static void main(String[] args) {
Object cm1 = ConfigC.getBean(CacheManager.class);
Object cm2 = ConfigA.getBean(CacheManager.class);
if (cm1 == cm2)
System.out.println("equals");
else
System.out.println("unequal");
}
}
i've already spent a lot of time to solve this problem - will be happy if anyone will help me
If I understand correctly A is a parent context with two children: B and C. You define cacheManager twice: in parent ConfigA and in one child ConfigC. Different application contexts can have the same beans, that's why you get two different instances.
In other words if you ask for cacheManager from ConfigC, it returns the one defined in that context. But if you ask for it from ConfigB or ConfigA, it'll return the one from ConfigA (other instance).
They are still singletons, but within the scope of a single application context. BTW can you describe what you want to achieve with this pretty complex architecture?

Categories