I have a Java Application running on a JBOSS.
This application gets data from several APIs and shows it on a webpage.
I want to cache the data so it doesn't need to call the APIs every time someone opens my webpage.
I want to cache 5 Lists or Strings for like 5 minutes. Is there any way to do it without a database?
You can use http sesion to persist information
Example
HttpSession misession= request.getSession(true);
Producto miproducto= new Producto(1,"telefono",300);
misession.setAttribute("producto",miproducto);
Link
HttpSession JBoss
Documenation
Jbos
If you are using springboot
You can use a singleton with application annotation
#Configuration
public class AppConfig {
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public PrototypeBean prototypeBean() {
return new PrototypeBean();
}
#Bean
public SingletonBean singletonBean() {
return new SingletonBean();
}
}
public class SingletonBean {
// ..
#Autowired
private PrototypeBean prototypeBean;
public SingletonBean() {
logger.info("Singleton instance created");
}
public PrototypeBean getPrototypeBean() {
logger.info(String.valueOf(LocalTime.now()));
return prototypeBean;
}
}
public static void main(String[] args) throws InterruptedException {
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext(AppConfig.class);
SingletonBean firstSingleton = context.getBean(SingletonBean.class);
PrototypeBean firstPrototype = firstSingleton.getPrototypeBean();
// get singleton bean instance one more time
SingletonBean secondSingleton = context.getBean(SingletonBean.class);
PrototypeBean secondPrototype = secondSingleton.getPrototypeBean();
isTrue(firstPrototype.equals(secondPrototype), "The same instance should be returned");
}
if you are using primer faces, you cna use #ApplicationScoped
#ApplicationScoped
An application-scoped managed bean instance is tied to the lifetime of the web application itself. There’s only one instance of an application-scoped managed bean throughout your web application. It is not the same but similar to a Singleton EJB.
Singleton
Related
I am somewhat new to Spring Framework. I have a web application written with Spring (4.2.1). I'm trying to expose metrics using Micrometer library and will be scraping with Prometheus.
The relevant structure of the application is this:
- core-module (JAR)
- webservice-module (WAR)
I created a PrometheusService class which is a bean defined in core-module. Defined inside the bean is the PrometheusMeterRegistry and Counter:
#Service
public class PrometheusService {
private static PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
private static Counter newAssetCounter = Counter
.builder("new_asset_counter")
.description("count of created assets")
.tags("region", "na")
.register(registry);
public PrometheusService() {
new JvmMemoryMetrics().bindTo(registry);
new DiskSpaceMetrics(new File("/")).bindTo(registry);
new ProcessorMetrics().bindTo(registry);
new UptimeMetrics().bindTo(registry);
}
public static PrometheusMeterRegistry getRegistry() {
return registry;
}
public Counter getNewAssetCounter() {
return this.newAssetCounter;
}
}
I created MetricsResource which is an HttpServlet that exposes the /metrics endpoint. When trying to #Autowire the PrometheusService bean, it was always null here. A quick search told me that HttpServlet isn't managed by Spring. If I wanted to #Autowire, I needed to add something like this:
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(webApplicationContext);
Now, I was able to #Autowire the PrometheusService bean within the Servlet.
The Counter defined in the bean gets incremented within the core-module. The MetricsResource doGet method writes the metrics stored in the PrometheusMeterRegistry.
#WebServlet("/metrics")
public class MetricsResource extends HttpServlet {
private PrometheusService promService; // #Autowired
private PrometheusMeterRegistry registry;
#Override
public void init() throws ServletException {
super.init();
// SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(webApplicationContext);
// promService = (PrometheusService) getServletContext().getAttribute("prometheusService");
// WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
// AutowireCapableBeanFactory ctx = context.getAutowireCapableBeanFactory();
// ctx.autowireBean(this);
}
#Override
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType(TextFormat.CONTENT_TYPE_004);
registry = promService.getRegistry();
Writer writer = resp.getWriter();
try {
registry.scrape(writer);
writer.flush();
} finally {
writer.close();
}
}
}
The problem though, is that the value of the Counter is always 0 at the /metrics endpoint.
No matter if it's #Autowired or if I'm manually trying to get the bean.
How could this be? My PrometheusService bean is a singleton. Even the PrometheusMeterRegistry and the Counter are marked static, so why am I getting a different object in my servlet? After some more searching, I found that Spring will create one singleton bean per container. So what I'm assuming is happening here is there are two containers or contexts. A main application context and a servlet context.
Some things I've tried:
Making PrometheusService implement ApplicationContextAware
Using a ServiceLocator class that implements ApplicationContextAware and returns beans
Adding context-params to web.xml
Using ServletContextAttributeExporter in app-context.xml
Using WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext())
I continue to get a new instance of the object. All I want to do is be able to create and expose custom metrics with Micrometer. Is my approach flawed? How can I access the correct bean from within my HttpServlet?
Spring dependency injection to other instance
http://senthadev.com/sharing-spring-container-between-modules-in-a-web-application.html
Spring dependency injection to other instance
ApplicationContext and ServletContext
Try processInjectionBasedOnServletContext(Object target, ServletContext servletContext).
I am searching for a way to read and parse a lot of data when the spring boot app is starting and be able to use these data later in other classes.
I started with a class DataRepository.java and annotated it with #Service to be able to inject it later. I'm planning to read the data here and to inject it in any other class I need the data.
But how can I achieve to parse the data just once and at app startup? The spring boot app should only be reachable if the parsing is done.
Your approach with #Service is 100% appropriate.
By default all beans are singletons, so if you parse data on bean creation (in constructor) it will be parsed only once, and this info can be used in other beans by simple injection.
Please note that if during data parsing you have to use other beans, you should be confident that all beans are completely constructed. For that you should use approach proposed by #jreznot:
https://stackoverflow.com/a/51783858/5289288
You can use ContextStartedEvent and handle it:
#Component
public class ContextStartedListener implements ApplicationListener<ContextStartedEvent> {
#Override
public void onApplicationEvent(ContextStartedEvent cse) {
System.out.println("Handling context start event. ");
}
}
See also: https://www.baeldung.com/spring-events
By default all beans in spring context are singletons. Spring guarantees that it will creates a bean just ones during context loading.
For example if you will have few contexts in your application it creates one instance for every context.
If you have just one context you can use these approaches:
initialize data in constructor. Data will initialized and ready to
use just after bean's instance creation.
#Component
public class DataRepository {
public DataRepository() {
... init data
}
}
use #Bean annotation withinit method. Allows you don't stick to Spring in
your data repository and initialize data after all beans were created.
public class DataRepository {
public void init() {
... init data
}
}
#Configuration
public class DataRepositoryConfiguration {
#Bean(initMethod = "init")
public DataRepository dataRepository() {
return new DataRepository();
}
use #Bean annotation and invoke init method. Allows you don't stick to
Spring in your data repository, but #Autowired field will uninitialized.
public class DataRepository {
public void init() {
... init data
}
}
#Configuration
public class DataRepositoryConfiguration {
#Bean
public DataRepository dataRepository() {
DataRepository dr = new new DataRepository();
dr.init();
return dr;
}
}
use #PostConstruct annotation. Initialize data after all beans was
created.
public class DataRepository {
#PostConstruct
public void init() {
... init data
}
}
Exception thrown during initializing will stop Spring's context initializing
You can use PostConstruct on any bean. For example
#Component
class DataLoad {
......
......
#PostConstruct
public void parseData() {
...... do your stuff here.......
}
}
With this the code inside parseData will be called only once. This is a very common way to do things in scenarios like when you want to load some configuration data from database at the start of the application and do it only once. In these cases you can #Autowired the repository class to the same class and use that in your #PostConstruct method and get data
I try to use #EnableSpringConfigured, but it is not work.
Engine.java
#Component
public class Engine {
public void run() {
System.out.println("Engine run");
}
}
Entity.java
#Component
#Configurable(autowire = Autowire.BY_TYPE)
public class Entity {
#Autowired
private Engine engine;
public void exec() {
if (engine != null)
engine.run();
else
System.out.println("exec failure");
}
}
EntityBuilder.java
#Component
public class EntityBuilder {
public Entity create() {
return new Entity();
}
}
EntityApplication.java
#Configuration
#ComponentScan
#EnableSpringConfigured
public class EntityApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EntityApplication.class);
EntityBuilder builder = context.getBean(EntityBuilder.class);
builder.create().exec();
}
}
The above four java in same package, I try run EntityApplication.java and expect to see "Engine run", but actual result always is "exec failure".
help! code is in https://github.com/lemonguge/spring/tree/master/spring-core/spring-aspect/src/main/java/cn/homjie/spring/aspect/newx
Spring can configure objects only if load time waving is enabled. You should mark your configuration with #EnableLoadTimeWeaving annotation
You need either load-time weaving or compile time weaving for the Configurable annotation
You declared Entity as a spring component, but inside EntityBuilder create()method, you manually creating Entity instance which means you
are not using Entity object which is created by spring container.
So how can spring auto wires Engine instance into your own Entity instance.
Reason why every time if (engine != null) becoming false.
If you declared your classes as spring components, spring container creates
the instances for them and we need to us them inorder to get the proper wiring system. Dont create your own instances if those classes connected with wiring.
vaadin-spring introduces a couple of Spring scoped objects, the vaadin-session and the vaadin-ui scope. It is necessary to have these two scopes bound before referencing any Vaadin objects in your spring context if:
they are decorated with the #VaadinSessionScope or #UIScope annotations, or
they through some dependency chain reference any bean that is decorated this way.
All runs perfectly well when you start it up in a servlet container like jboss or tomcat. The question is:
If you would like to load a spring application context that contains any of the vaadin beans so decorated for unit testing purposes, how can you create a minimal test that allows the context to be loaded and accessed without starting up a web application container?
Spring MVC is very good at this but when you're using vaadin-spring it's not as straightforward - the relevant vaadin components are highly connected.
(The following example of how to construct a set of Vaadin components to allow access through the abovementioned scopes does not include configuration of the full container, just the minimum required to get a functioning application context.)
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigWebContextLoader.class)
#WebAppConfiguration
public class SpringConfigurationTest extends Assert {
#Configuration
#ComponentScan({ "org.example" }) // contains SomeClassReferencingASpringVaadinBean.class
public static class Config {
}
#Autowired
WebApplicationContext applicationContext;
class MyDeploymentConfiguration extends DefaultDeploymentConfiguration {
public MyDeploymentConfiguration(Class<?> servletClass, Properties initParameters) {
super(servletClass, initParameters);
initParameters.put(Constants.SERVLET_PARAMETER_UI_PROVIDER, DefaultUIProvider.class.getName());
}
}
class MyVaadinServlet extends VaadinServlet {
#Override
public String getServletName() {
return getClass().getSimpleName();
}
}
class MyUI extends UI {
#Override
protected void init(VaadinRequest request) {
}
}
#Before
public void setupVaadinScopes() throws Exception {
MyVaadinServlet vaadinServlet = new MyVaadinServlet();
MyDeploymentConfiguration deploymentConfiguration = new MyDeploymentConfiguration(MyVaadinServlet.class,
new Properties());
VaadinServletService vaadinService = new VaadinServletService(vaadinServlet, deploymentConfiguration);
VaadinServletRequest vaadinRequest = new VaadinServletRequest(new MockHttpServletRequest(), vaadinService);
// creates vaadin session and vaadin ui, binds them to thread
VaadinSession vaadinSession = vaadinService.findVaadinSession(vaadinRequest);
Integer uiId = Integer.valueOf(vaadinSession.getNextUIid());
UI ui = new MyUI();
ui.setSession(vaadinSession);
UI.setCurrent(ui);
ui.doInit(vaadinRequest, uiId, null);
vaadinSession.addUI(ui);
}
#Test
public void test0() {
try {
applicationContext.getBean(SomeClassReferencingASpringVaadinBean.class);
} catch (Exception e) {
fail("scopes were probably not set up correctly");
}
}
}
Currently I am using a singleton class to read and load the propertied file. I get an instance of this in any class where I want to use a property value.
Would not it be better to use a static class instead which can be loaded once (when server started or something .. ) instead of using a singleton ? Why and why not ?
Moreover how can we load a static class OnServerStart or when war gets deployed.
PS: Project is web application
Singleton is better for dependency injection and unit testing than statics.
You may inject an instance of singleton class or a Mock of that type to any other class under test.
public class PropertiesHolder {
private static final PropertiesHolder INSTANCE = new PropertiesHolder();
private final Properties props;
private PropertiesHolder() {
props = load();
}
public static PropertiesHolder getInstance() {
return INSTANCE;
}
public String getProperty(String key) {
return props.getProperty(key);
}
private Properties load() {
...
}
}
Then you may mock PropertiesHolder in your test:
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#Mock private PropertiesHolder holder;
#Test
public void testSomething() {
SomeService service = new SomeService(holder);
when(holder.getProperty("foo")).thenReturn("bar");
String result = service.doSomething();
assertEquals(...)
}
}
For production code you may use:
new SomeService(PropertiesHolder.getInstance());
Or even better, use DI framework, e.g. Spring, for wiring a beans. PropertiesHolder would be a generic bean with factory method getInstance() and the scope 'singleton'.
If you're using Spring in your web application I'd suggest using with it's PropertyPlaceholderConfigurer.
If you don't want to use Spring for that and need to do some actions (e.g. loading property file) on servlet when webapp is started then use ServletContextListener as Bhesh Gurung has suggested.