Bean mit Scope globalSession


#1

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 [INLINE]2017-02-20 15:23:18,870 INFO [stdout] (default task-37) Hallo p1 12[/INLINE]

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


#2

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.


#3

[QUOTE=Unregistered;145012]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.

[QUOTE=Unregistered;145012]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?[/QUOTE]

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

[QUOTE=Unregistered;145012]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]

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: