How to reference Spring Beans from Everywhere!

Λοπόν, με αφορμή κάτι που με ταλαιπωρούσε γράφω τον παρακάτω οδηγό έτσι ώστε να δείξω πως μπορείς να καλέσεις ενα Spring Bean απο πρακτικά οπουδήποτε.

Ουσιαστικά έχουμε τις εξής περιπτώσεις περιπτώσεις για να καλέσουμε ένα bean

  1. Σε Spring non Web Application
  2. Σε Spring Web Application
    1. Μέσα απο κάποιον controller
    2. Μέσα σε κάποιο servlet
    3. Μέσα σε κάποιο implementation ή οποιαδήποτε άλλη Business Logic Class (aka μια απλή java class)

Θα τις πάρουμε λοιπόν μία-μία για να δούμε πως θα δουλέψουμε.

Πρώτα όμως θα φτιάξουμε ένα Bean το οποίο και θα καλούμε κάθε φορά μέσα στο κώδικά μας.

Το Spring Bean δεν είναι τίποτε άλλο απο ένα POJO (Plain Old Java Object) το οποίο με το που γίνεται initialize το Spring Context οι setters του “γεμίζουν” με ό,τι ορίζουμε εμείς στο context.xml (το κύριο xml που ορίζοντε όλοι οι παράμετροι του Spring, θα μπορούσε να λέγεται και διαφορετικά)

Στο παράδειγμά μας θα φτιάξω ένα Constants Bean το οποίο θα περιέχει πχ “σταθερές” που θέλω να χρησημοποιώ παντού και να τις ελέγχω απο το XML

Επι του προκειμένου θα γεμίζω 3εις μεταβλητές με τις μαθηματικές σταθερές

  • π = 3,14
  • e = 2,71
  • γ = 0,57 (σταθερα Euler)

Φτιάχνω λοιπόν το Constants.java (το Bean μου)

package gr.zenika.j2eegr.examples

public class Constants {

 private String pi;
 private String epsilon;
 private String gamma;

 private String pi;
 private String epsilon;
 private String gamma;

 public String getPi() {
   return pi;
 }
 public void setPi(String pi) {
   this.pi = pi;
 }
 public String getEpsilon() {
   return epsilon;
 }
 public void setEpsilon(String epsilon) {
   this.epsilon = epsilon;
 }
 public String getGamma() {
   return gamma;
 }
 public void setGamma(String gamma) {
   this.gamma = gamma;
 }

}

Τώρα θα ορίσουμε το Bean αυτό στο context.xml

<bean id="constants" class="gr.zenika.j2eegr.examples.Constants" >
 <property name="pi" value="3,14" />
 <property name="epsilon" value="2,71" />
 <property name="gamma" value="0,57" />
</bean>

Περισσότερα για τα Spring Beans θα βρείτε έδω…
Οπότε είμαστε έτοιμοι να ξεκινήσουμε…!

1. Σε Spring Application

Έχοντας τη διαδρομή (path) του context.xml στο classpath κάνουμε το εξής

// Αρχικοποιούμε το application context, μπορούμε με κόμματα να έχουμε πολλα xml
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"context.xml"});

// παίρνουμε το bean
Constants constants = context.getBean("constants", Constants.class);

Τόσο απλά!

Οπότε μπορούμε να χρησημοποιήσουμε το Spring με όλα τα καλούδια απο οποιαδήποτε stand alone εφαρμογή!

2.A. Σε Spring Web Application μέσα σε Controller

Εδώ είναι πολύ εύκολα τα πράγματα γιατι θα χρησημοποιήσουμε το @Autowired annotation που υπάρχει απο το spring 2.5 και μετα

@Controller
public class tokenService {

 @Autowired
 private Constants constants;

...

}

Και έτσι έχουμε το constants διαθέσημο σε όλη τη Class. ΠΡΟΣΟΧΗ το όνομα της μεταβλητής να είναι το ίδιο με το id στο όρισμα του Bean στο XML!

2.Β. Σε Spring Web Application μέσα σε Servlet

Βέβαια δε μπορώ να καταλάβω γιατι κάποιος να χρησημοποιήσει servlet σε Spring MVC εφαρμογή αλλά αυτό είναι άλλο θέμα… 🙂

Το μόνο που έχουμε να κάνουμε εαι να βάλουμε μέσα στη doGet() ή την doPost() κλπ τις γραμμές

//Παίρνουμε το servlet Context
ServletContext context = getServletConfig().getServletContext();

//απο εκεί παίρνουμε το Spring Application context
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());

//και στο τέλος το Bean το οποίο επειδή γυρνάει τύπου Object το κάνουμε cast στο τύπο που το έχουμε ορίσει (Constants)
Constants constants (Constants) = context.getBean("constants");

2.C. Σε Spring Web Application μέσα σε κάποιο implementation ή οποιαδήποτε άλλη Business Logic Class ακόμα και Legacy code
Εδώ λοιπόν είναι λίγο περίπλοκα τα πράγματα γιατί

  1. Δεν είναι stand alone εφαρμογη οπότε αφενός δε ξέρουμε το path που βρίσκεται και αφετέρου δεν είμαστε και πολυ σίγουροι ότι το XML είναι μέσα στο classpath
  2. Επειδή είναι deployed σε κάποιο application server και ανάλογα με τις ρυθμίσεις του και το λειτουργικό στο οποίο είναι επάνω μπορεί το XML να είναι LOCKED for Reading οπότε και να βρούμε το path που βρίσκεται, μπορεί να μη μπορεί το thread που θα ανοίξουμε να το διαβάσει!

Οπότε η στρατηγική που θα ακολουθήσουμε είναι η εξής.

Μια και ενα Bean είναι απλα ένα pojo το οποίο μπορούμε να το αρχικοποιήσουμε μέσα απο το XML, on load του Spring Web App, θα φτιάξουμε ένα άλλο Bean το οποίο, το μόνο που θα κάνει είναι ότι θα δέχεται μέσα του το Spring Context (το οποίο θα περνάμε σα παράμετρο για την αρχικοποίησή του μέσα απο το XML) και θα έχει μια μέθοδο που απο αυτό το context θα φέρνει το Bean που θέλω! Αυτό το Bean (ας το ονομάσουμε SpringApplicationContext) θα μπορούν μετά να το χρησημοποιήσουν όλα τα implementations!

Το SpringApplicationContext.java είναι ώς εξής

package gr.zenika.j2eegr.examples

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class SpringApplicationContext implements ApplicationContextAware {

 private static ApplicationContext CONTEXT;

 public void setApplicationContext(ApplicationContext context) throws BeansException {
 CONTEXT = context;
 }

 public static Object getBean(String beanName) {
 return CONTEXT.getBean(beanName);
 }

}

Στο context.xml αρχικοποιούμε το Bean βάζοντας

<bean id="springApplicationContext" class ="gr.zenika.j2eegr.examples.SpringApplicationContext" />

Οπότε μέσα στη Class που θέλουμε να το καλέσουμε γράφουμε

package gr.zenika.j2eegr.examples

public class MyMethodImpl {

 Constants constants = (Constants) SpringApplicationContext.getBean("constants");

 public String myFoo(){
 ... do something ...
 }

}

Και αυτό ήταν!

Facebook Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.