Bean mit Scope globalSession

Ich bins mal wieder :slight_smile:

Ich bin grad dabei ein Webprojekt zu schreiben, welches Serverseitig Daten von verschiedenen Hosts sammeln soll. Dies Sollten nach Möglichkeit bei Server hinterlegt werden und nur alle X Sekunden/Minuten erneut abgerufen werden. Für einen Client könnte ich bei jedem Seitenaufrauf die Daten laden lassen, bei mehreren hingegen würde das für recht viel Traffic sorgen.

Mein Ansazt war, dass ich eine Bean programmiere, die diese Daten zur Verfügung stellt und beim Aufrufen einen Timestamp prüft, ob die Daten nur ausgegeben oder aktualiesiert werden müssen. Also im Grunde sowas wie:

    //Daten aktualisieren
}
//Daten ausgeben

Im Internet habe ich mir dazu bereits diverse Hinweise zum Thema Scope durchgelesen und denke ich bräuchte hier eine Bean mit scope=„globalSession“, da diese Daten ja für alle Clients zählen soll. Aktuell sieht das ganze bei mir so aus:

scanviewBeans.xml
[XML]<?xml version="1.0" encoding="UTF-8"?>

<bean id="valibean" class="beans.ValiBeanImpl"/>

[/XML]

ValiBean.java


public interface ValiBean {
	
	void sayHelloBean(String maschine);

}```

ValiBeanImpl.java
```package beans;

import java.util.Random;

import org.springframework.context.annotation.Bean;

public class ValiBeanImpl implements ValiBean {

	private int random_p1 = 0;
	private int random_p2 = 0;
	private int random_p3 = 0;
	private int random_p4 = 0;
	
	@Bean
	@Scope("session")
	public void sayHelloBean(String maschine) {
		if(maschine.equals("p1")) {
			if(random_p1 == 0) {
				Random r = new Random();
				random_p1 = r.nextInt(100);
			}
			random_p1 ++;
			System.out.println("Hallo " + maschine + " " + random_p1);
		} else if(maschine.equals("p2")) {
			if(random_p2 == 0) {
				Random r = new Random();
				random_p2 = r.nextInt(100);
			}
			random_p2 ++;
			System.out.println("Hallo " + maschine + " " + random_p2);
		} else if(maschine.equals("p3")) {
			if(random_p3 == 0) {
				Random r = new Random();
				random_p3 = r.nextInt(100);
			}
			random_p3 ++;
			System.out.println("Hallo " + maschine + " " + random_p3);
		} else if(maschine.equals("p4")) {
			if(random_p4 == 0) {
				Random r = new Random();
				random_p4 = r.nextInt(100);
			}
			random_p4 ++;
			System.out.println("Hallo " + maschine + " " + random_p4);
		}
	}
	
}```

ValiBeanTest
```package beans;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ValiBeanTest {

	@SuppressWarnings("resource")
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("scanviewBeans.xml");
		
		ValiBean vali = (ValiBean) context.getBean("valibean");
		vali.sayHelloBean("p1");
		
		ValiBean vali2 = (ValiBean) context.getBean("valibean");
		vali2.sayHelloBean("p1");
		
		ValiBean vali3 = (ValiBean) context.getBean("valibean");
		vali3.sayHelloBean("p2");
		
		ValiBean vali4 = (ValiBean) context.getBean("valibean");
		vali4.sayHelloBean("p1");
		
		ValiBean vali5 = (ValiBean) context.getBean("valibean");
		vali5.sayHelloBean("p2");
	}
	
}```

Das ganze funktioniert dann so auch ganz gut. Problematisch wird es dann, wenn ich beim Seitenaufruf mir die ApplicationContext laden will, da ich leider nicht weiß, wie ich die wiederverwenden soll. Aktuell wird im Controller auf dem Server das ganze zu Testzwecken so ausgelesen:

```package controller;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@WebAppConfiguration
public class ViewController {

	@SuppressWarnings("resource")
	@RequestMapping("/scanner")
	public ModelAndView getScanner() {
		ModelAndView mav = new ModelAndView("scanner");
		
		int i = new Random().nextInt(40);
		String maschine = "p" + ((i % 4) +1);
		ApplicationContext context = new ClassPathXmlApplicationContext("scanviewBeans.xml");
		ValiBean vali = (ValiBean) context.getBean("valibean");
		vali.sayHelloBean(maschine);
		
		return mav;
	}

}

Eine Ausgabe sieht dann im Log zum Beispiel so aus:

2017-02-20 15:23:13,507 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (default task-23) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5e585f64: startup date [Mon Feb 20 15:23:13 CET 2017]; root of context hierarchy
2017-02-20 15:23:13,508 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (default task-23) Loading XML bean definitions from class path resource [scanviewBeans.xml]
2017-02-20 15:23:13,515 INFO  [stdout] (default task-23) Hallo p3 93

2017-02-20 15:23:16,337 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (default task-25) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@41ad7220: startup date [Mon Feb 20 15:23:16 CET 2017]; root of context hierarchy
2017-02-20 15:23:16,337 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (default task-25) Loading XML bean definitions from class path resource [scanviewBeans.xml]
2017-02-20 15:23:16,342 INFO  [stdout] (default task-25) Hallo p1 20

2017-02-20 15:23:16,738 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (default task-27) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@49dbf42d: startup date [Mon Feb 20 15:23:16 CET 2017]; root of context hierarchy
2017-02-20 15:23:16,738 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (default task-27) Loading XML bean definitions from class path resource [scanviewBeans.xml]
2017-02-20 15:23:16,744 INFO  [stdout] (default task-27) Hallo p3 92

2017-02-20 15:23:17,169 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (default task-29) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@cb186da: startup date [Mon Feb 20 15:23:17 CET 2017]; root of context hierarchy
2017-02-20 15:23:17,169 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (default task-29) Loading XML bean definitions from class path resource [scanviewBeans.xml]
2017-02-20 15:23:17,173 INFO  [stdout] (default task-29) Hallo p1 10

2017-02-20 15:23:17,585 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (default task-31) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@f808736: startup date [Mon Feb 20 15:23:17 CET 2017]; root of context hierarchy
2017-02-20 15:23:17,585 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (default task-31) Loading XML bean definitions from class path resource [scanviewBeans.xml]
2017-02-20 15:23:17,590 INFO  [stdout] (default task-31) Hallo p3 91

2017-02-20 15:23:18,003 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (default task-33) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@70d13637: startup date [Mon Feb 20 15:23:18 CET 2017]; root of context hierarchy
2017-02-20 15:23:18,003 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (default task-33) Loading XML bean definitions from class path resource [scanviewBeans.xml]
2017-02-20 15:23:18,010 INFO  [stdout] (default task-33) Hallo p4 80

2017-02-20 15:23:18,403 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (default task-35) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5f30d6b2: startup date [Mon Feb 20 15:23:18 CET 2017]; root of context hierarchy
2017-02-20 15:23:18,403 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (default task-35) Loading XML bean definitions from class path resource [scanviewBeans.xml]
2017-02-20 15:23:18,411 INFO  [stdout] (default task-35) Hallo p1 23

2017-02-20 15:23:18,865 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (default task-37) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@34338852: startup date [Mon Feb 20 15:23:18 CET 2017]; root of context hierarchy
2017-02-20 15:23:18,865 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (default task-37) Loading XML bean definitions from class path resource [scanviewBeans.xml]
2017-02-20 15:23:18,870 INFO  [stdout] (default task-37) Hallo p1 12

Wichtig dabei sind bei jedem Block die letzte Zeile, im letzten Beispiel also 2017-02-20 15:23:18,870 INFO [stdout] (default task-37) Hallo p1 12

Hierbei würde ich eine Ausgabe erwarten die zum Beispiel so aussieht:

2017-02-20 15:23:18,870 INFO  [stdout] (default task-37) Hallo p1 12
2017-02-20 15:23:18,870 INFO  [stdout] (default task-37) Hallo p1 13
2017-02-20 15:23:18,870 INFO  [stdout] (default task-37) Hallo p1 14
2017-02-20 15:23:18,870 INFO  [stdout] (default task-37) Hallo p1 15
2017-02-20 15:23:18,870 INFO  [stdout] (default task-37) Hallo p1 16

Allerdings berechnet er über den Random immer wieder die Zahl neu, obwohl Sie in der ValiBeanImpl.java nicht 0 sein dürfte, da ich ja vorher über den Scope festlege, dass er die Bean erneut verwenden soll. Hat das damit zu tun, dass ich die ApplicationContext jedesmal neu lade? Und wie kann ich das ganze ggf. umgehen?

Danke schonmal. Mit freundlichen Grüßen
Gossi

Du möchtest keinen globalSession, sondern den Singleton-Scope. Das ist der Standard für Spring Beans, wenn man nichts anderes angibt. Das @Bean und @Scope in der ValiBeanImpl bringt leider hier überhaupt nichts. @Bean sollte man und in mit @Configuration annotierten Klassen nutzen, das brauchst du aber überhaupt nicht.

Im Controller brauchst du keinen Zugriff auf den ApplicationContext, sondern lässt dir ValiBean einfach injecten (über den Konstruktiv oder per Setter).

Um dir genau zu sagen wie das in deinem Fall geht fehlen leider Informationen. Nutzt du Spring-Boot oder nur Spring? Baust du ein WAR und deployst das in einen Tomcat? Ist das oben der komplette Code?

Alles in allem würde ich dir raten, dir nochmal die Grundlagen von Spring und Dependency Injection anzuschauen. Ich habe das Gefühl, dass du dort noch Lücken hast, die dich in Zukunft weiter frustrieren werden, wenn du diese jetzt nicht schließt.

[QUOTE=Unregistered]Du möchtest keinen globalSession, sondern den Singleton-Scope. Das ist der Standard für Spring Beans, wenn man nichts anderes angibt. Das @Bean und @Scope in der ValiBeanImpl bringt leider hier überhaupt nichts. @Bean sollte man und in mit @Configuration annotierten Klassen nutzen, das brauchst du aber überhaupt nicht.

Im Controller brauchst du keinen Zugriff auf den ApplicationContext, sondern lässt dir ValiBean einfach injecten (über den Konstruktiv oder per Setter).[/QUOTE]

Alles klar, danke. Werd mir das mal genauer anschauen.

Ich nutze nur Spring und baue daraus eine WAR die ich in einen Wildfly (JBoss) Deploye.

Darüber hatte ich auch schon nachgedacht und habe mir jetzt mal ein Springtutorial rausgesucht, welches ich diese Woche mal durchgehen möchte.

Alles in allem nochmals danke für die Hilfe :slight_smile: