What is SpringBoot's session scope?Why won't this work? - java

I have SpringBoot application code like this:
class HelloMessageGenerator{
public static int num = 0;
public HelloMessageGenerator(){
System.out.println("new session");
}
public void doSomething(){
System.out.println("doSomething");
}
}
#Controller
class ScopesController {
#Resource(name = "sessionScopedBean")
HelloMessageGenerator sessionScopedBean;
#Bean
#SessionScope
public HelloMessageGenerator sessionScopedBean() {
return new HelloMessageGenerator();
}
#RequestMapping("/")
public String getSessionScopeMessage(final Model model) {
sessionScopedBean.doSomething();
return "hello";
}
}
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
And i've set server.sessionTimeout=1.
But when i refresh the browser page, it doesn't process the constructer of HelloMessageGenerator,
the output is like that:
I thought the output should be:
new session
doSomething
new session
doSomething
new session
doSomething

Related

ApplicationListener<SessionDestroyedEvent> is not called

I need to audit timeout logOut event, I searched a bit and find a solution. But it doesn't work. The event method is not called at all when the user logs out or timeout.
This is my code:
ObjectLock.java:
#Component
public class ObjectLock implements ApplicationListener<SessionDestroyedEvent> {
#Override
public void onApplicationEvent(SessionDestroyedEvent event)
{
List<SecurityContext> lstSecurityContext = event.getSecurityContexts();
String userName;
for (SecurityContext securityContext : lstSecurityContext)
{
userName = (String)securityContext.getAuthentication().getPrincipal();
System.out.println("Log Out " + userName);
// ...
}
}
}
Application.java:
public class Application {
public static void main(String[] args) throws Exception {
TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));
SpringApplication application = new SpringApplication( Application.class );
application.addListeners(new ObjectLock());
ConfigurableApplicationContext context = application.run(args);
// ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
}
}
Anyone can tell me what is wrong? Thanks.
Add the following code/class and then the listener will get called:
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.session.HttpSessionEventPublisher;
#Configuration
public class ApplicationConfig {
#Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
}
}

NullPointedException when using Spring RestTemplate in Java

I'm using the latest Springframework, and having issues trying to GET an int from my server. All code was writen in Java.
When I interact with the server throught browser everything is OK. And when interacting with the server through the client I'm getting a NullPointerException.
Keep in mind I am a beginner software student.
Server Code (I tried both, works fine when using browser):
public class RestController {
private GameSession gameSession = new GameSession();
#RequestMapping(value = "registerPlayer")
public int registerPlayer(#RequestParam("name") String name, #RequestParam("mode") boolean mode) {
return gameSession.registerPlayer(name, mode);
}
#RequestMapping(value = "registerPlayer/{name}/{mode}")
public int registerPlayer(#PathVariable String name, #PathVariable boolean mode) {
return gameSession.registerPlayer(name, mode);
}
}
Client Code (again tried both, with the same result):
#Component
public class GameSessionClient implements ISeaBattleGame{
#Autowired
private RestOperations restOperations;
private String url;
#Override
public int registerPlayer(String name, boolean singlePlayerMode) {
url = "http://localhost:8080/" + "registerPlayer?name=" + name + "&mode=" + (singlePlayerMode ? 1 : 0);
return restOperations.getForObject(url, int.class);
}
#Override
public int registerPlayer(String name, boolean singlePlayerMode) {
url = "http://localhost:8080/" + "registerPlayer/" + name + "/" + (singlePlayerMode ? 1 : 0);
return restOperations.getForObject(url, int.class);
}
}
RestConfig Code:
#Configuration
public class RestConfig {
#Bean
public RestOperations createRestTemplate(final ClientHttpRequestFactory clientHttpRequestFactory){
return new RestTemplate(clientHttpRequestFactory);
}
#Bean
public ClientHttpRequestFactory clientHttpRequestFactory(#Value("${connect.timeout}") final int connectTimeout, #Value("${read.timeout}") final int readTimeout){
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpComponentsClientHttpRequestFactory.setReadTimeout(readTimeout);
httpComponentsClientHttpRequestFactory.setConnectTimeout(connectTimeout);
return httpComponentsClientHttpRequestFactory;
}
}
App Code:
#SpringBootApplication
public class App implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
#Autowired
private GameSessionClient gameSessionClient;
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
#Override
public void run(String... args) throws Exception {
int playerNr = gameSessionClient.registerPlayer("test", true);
logger.info("Response: {}", playerNr);
}
}
The return restOperations.getForObject(url, int.class); results in a java.lang.NullPointerException
url: http://localhost:8080/registerPlayer/test/1 or http://localhost:8080/registerPlayer?name=test&mode=1 both result in 1 when using my browser
Any help would be much appreciated, as I'm getting pretty confused from this.
Update you code to below..will remove the NullPointer Exception your getting:
#Bean
public RestOperations restOperations(final ClientHttpRequestFactory clientHttpRequestFactory){
return new RestTemplate(clientHttpRequestFactory);
}
and do this , instead of "Application.class":
public static void main(String[] args){
SpringApplication.run(App.class, args);
}

Spring/SPeL: condition specific Cache control from one class to another

tl;dr;
I am looking for a way to set a "condition" attribute on a Spring Cacheable annotation from another class. Is there such a way?
Using Spring Cache where it should cache ONLY whenever a certain method has been invoked. This method is in ClassA, the method (data) to cache is in ClassB. What I want to do is something like this:
public ClassA implements myInterface {
...
private Boolean inProcess = false;
public void cacheWhenThisMethodCalled() {
try {
inProcess = true;
// do work here, somewhere along the line
// the method in ClassB gets called
} finally {
inProcess = false;
}
}
ClassB:
public ClassB {
...
#Cacheable(cacheNames={"aCache"}, condition="#classA.inProcess")
public ValueClass findValueClass(UUID id)
However, I can't find the right condition for the SPeL to work. I have tried many combinations, none successfully. ClassA is a SpringBean, but the #Bean annotation returns the Interface, not the class. Can this be made to work? Or is there a better way?
Use a ThreadLocal - you would need to do that anyway for thread safety - otherwise a different thread can change the field.
This works fine...
#SpringBootApplication
#EnableCaching
public class So47580936Application {
public static void main(String[] args) {
SpringApplication.run(So47580936Application.class, args);
}
#Bean
public ApplicationRunner runner(Bar bar) {
return args -> {
bar.cacheFromHere();
bar.dontCacheFromHere();
};
}
#Component
public static class Foo {
#Cacheable(cacheNames = "foos", condition = "T(com.example.So47580936Application$Bar).cacheit()")
public String foo() {
System.out.println("here");
return "foo";
}
}
#Component
public static class Bar {
private static final ThreadLocal<Boolean> cacheit = new ThreadLocal<>();
#Autowired
private Foo foo;
public static boolean cacheit() {
return cacheit.get() == null ? false : cacheit.get();
}
public void cacheFromHere() {
try {
this.cacheit.set(true);
System.out.println("Cache:" + this.foo.foo());
System.out.println("Cache:" + this.foo.foo());
}
finally {
this.cacheit.remove();
}
}
public void dontCacheFromHere() {
System.out.println("Don't:" + this.foo.foo());
System.out.println("Don't:" + this.foo.foo());
}
}
}
result:
here
Cache:foo
Cache:foo
here
Don't:foo
here
Don't:foo
EDIT
Or, you can just make the ThreadLocal a #Bean ...
#SpringBootApplication
#EnableCaching
public class So47580936Application {
public static void main(String[] args) {
SpringApplication.run(So47580936Application.class, args);
}
#Bean
public ApplicationRunner runner(Bar bar) {
return args -> {
bar.cacheFromHere();
bar.dontCacheFromHere();
};
}
#Bean
public ThreadLocal<Boolean> cacheit() {
return new ThreadLocal<>();
}
#Component
public static class Foo {
#Cacheable(cacheNames = "foos", condition = "#cacheit.get() ?: false")
public String foo() {
System.out.println("here");
return "foo";
}
}
#Component
public static class Bar {
#Autowired
private ThreadLocal<Boolean> cacheit;
#Autowired
private Foo foo;
public void cacheFromHere() {
try {
this.cacheit.set(true);
System.out.println("Cache:" + this.foo.foo());
System.out.println("Cache:" + this.foo.foo());
}
finally {
this.cacheit.remove();
}
}
public void dontCacheFromHere() {
System.out.println("Don't:" + this.foo.foo());
System.out.println("Don't:" + this.foo.foo());
}
}
}

AbstractRoutingDataSource strange behaviour

I am newbie in Spring.
I use AbstractRoutingDataSource to change db connection in runtime and SpringBoot
My code is similar to this https://spring.io/blog/2007/01/23/dynamic-datasource-routing but beans are configured programatically.
public class DatabaseContext {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setDatabaseType(String string) {
contextHolder.set(string);
}
public static String getDatabaseType() {
return (String) contextHolder.get();
}
public static void clearDatabaseType() {
contextHolder.remove();
}
}
Everything works fine when I change context like that (pseudocode):
public class Application {
#Autowired
private MyCrudRepository repository;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override run(){
DatabaseContext.changeContext("db1");
repository.findAll(); //data from db1 like expected
DatabaseContext.changeContext("db2");
repository.findAll(); //data from db2 like expected
}
}
but when I change context in servlet class (pseudocode)
#Controller
public class MyWebController{
#RequestMapping(someMapping)
HttpEntity someMethod(){
DatabaseContext.changeContext("db1");
repository.findAll(); //data from db1 like expected
DatabaseContext.changeContext("db2");
repository.findAll(); //data from db1
}
}
Context change just one time and I have no idea what's wrong.

How use #Autowired with Annotation config?

i create simple spring project and i need to use annotation #Autowired but when i run project, i get exception NullPointerException.
This is my classes:
Main.java
public class Main {
#Autowired
private static InjectClass injectClass;
public static void setInjectClass(InjectClass injectClass) {
Main.injectClass = injectClass;
}
public static void main(String[] args) {
injectClass.hello(); //NullPointerException
}
}
ConfigurationBean
#Configuration
public class ConfigurationBean {
#Bean
public InjectClass injectClass(){
return new InjectClass();
}
}
InjectClass
public class InjectClass {
public void hello(){
System.out.println("Autowired success!");
}
}
You need to initiate application contex before using any bean.
You can do it by writing following code in starting of your main method.
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
ConfigurationBean.class);

Categories