FREE

ΕΝΟΤΗΤΑ 3 SPRING - CONSTRUCTOR-ARG ATTRIBUTES

Στο σημερινό δωρεάν μάθημα Spring Framework θα δούμε τις επιπρόσθετες επιλογές που έχουμε όταν χρησιμοποιούμε το constructor-arg στο Spring configuration αρχείο. Ήδη έχουμε χρησιμοποιήσει το ref για να κάνουμε inject στην κλάση μας ένα αντικείμενο από μια άλλη κλάση. Αν όμως χρησιμοποιείτε ένα IDE όπως το IntelliJ θα έχετε παρατηρήσει ότι όταν γράφατε το ref εμφανίστηκαν και άλλες επιλογές.

Δωρεάν Μαθήματα και Σεμινάρια Spring Framework

Αν και ο κύριος μας στόχος είναι να φτάσουμε στις ενότητες όπου όλο το configuration θα γίνεται μέσα από annotations, καλό θα ήταν να δούμε μερικές από τις δυνατότητες του constructor-arg χωρίς να μπούμε σε πολλές λεπτομέρειες.

Πριν ξεκινήσουμε ας προσθέσουμε άλλη μια κλάση στο project, που είχαμε δημιουργήσει στην Ενότητα 2, και ας την ονομάσουμε Passenger. Η κλάση είναι μια απλή περιγραφή του επιβάτη όπως δείχνει και ο παρακάτω κώδικας:

Passenger.java


package com.mycompany.flights;

public class Passenger {
    private String passengerName;
    private int passengerAge;
    private boolean European;

    public Passenger(String passengerName, int passengerAge, boolean European) {
        this.passengerName = passengerName;
        this.passengerAge = passengerAge;
        this.European = European;
    }

    public String toString(){
        return "Passenger Name: " + this.passengerName + ", Age: " + this.passengerAge
            +", is European: " +this.European;
    }
}

	

Μπορούμε τώρα να χρησιμοποιήσουμε το value attribute του constructor-arg έτσι ώστε όχι μόνο να δημιουργήσουμε το αντικείμενο αλλά να δώσουμε και αρχικές τιμές στις μεταβλητές του. Μπορείτε να βρείτε την σχετική θεωρία στο documentation.

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html

Δωρεάν Μαθήματα και Σεμινάρια Spring Framework

Προσθέτοντας και αυτή την πληροφορία, το beans.xml αρχείο γίνεται ως εξής:

beans.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http: //www.springframework.org/schema/beans"        
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

	 <bean id="myDailyOfferService" class="com.mycompany.flights.DailyOfferServiceImpl">
	</bean>
	    
	<bean id="myFlight" class="com.mycompany.flights.AthensFlight">
	<constructor-arg ref="myDailyOfferService" />
	</bean>

	 <bean id="flightPassenger" class="com.mycompany.flights.Passenger">
		    
		<constructor-arg value="Michail" />
		    
		<constructor-arg value="50" />
		    
		<constructor-arg value="True" />
	</bean>
	    
</beans>


	

Ας αλλάξουμε και την HelloFlightApp κλάση έτσι ώστε να καλεί ένα αντικείμενο Passenger. Όταν καλέσουμε την μέθοδο toString( ) στο αντικείμενο, θα πρέπει να δούμε τις πληροφορίες που έχουμε ήδη περάσει στον Passenger μέσα από το constructor-arg χρησιμοποιώντας το value attribute.

HelloFlightApp.java


package com.mycompany.flights;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class HelloFlightApp {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("flight.xml");
        Flight myFlight = context.getBean("myFlight", Flight.class);
        Passenger passenger = context.getBean("flightPassenger", Passenger.class);
        System.out.println(passenger.toString());
        System.out.println(myFlight.getDestination());
        System.out.println(myFlight.getDailyOffer());
        context.close();
                
                
    }
}


	

Output


Passenger Name: Michail, Age: 50, is European: true
Your final destination is Athens Greece
You have received 20% discount on your next trip to Athens

	

Ο τρόπος που το Spring Framework χρησιμοποίησε για να περάσει τις τιμές στον constructor είναι ο εξής:

1. Πρώτα έψαξε να βρει ποιος constructor από την κλάση Passenger δέχεται τρεις μεταβλητές.

2. Αν βρει περισσότερους από έναν constructor, τότε ψάχνει να βρει εκείνον τον constructor ή constructors που δέχονται τα συγκεκριμένα data types στις μεταβλητές τους.

3. Τέλος, ψάχνει να βρει εκείνον τον constructor ο οποίος ικανοποιεί τους δύο πρώτους όρους και επίσης δέχεται τις μεταβλητές με την σωστή σειρά.

Τι σημαίνουν όλα αυτά? Σημαίνουν ότι, αν και είναι βολικό να περνάμε κάποια στοιχεία μέσα από το beans.xml κυρίως για testing λόγους, όμως θα πρέπει να περαστούν με τα σωστά data types και με την σωστή σειρά. Μην ξεχνάτε ότι μέσα από τον constructor-arg περάσαμε τα valueς ξέροντας ήδη τον constructor. Αν είχαμε βάλει τις τιμές λάθος, όπως δείχνει το παρακάτω παράδειγμα, θα λαμβάναμε το εξής μήνυμα από το Spring Framework όταν προσπαθήσουμε να το τρέξουμε:

beans.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http: //www.springframework.org/schema/beans"        
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

	 <bean id="myDailyOfferService" class="com.mycompany.flights.DailyOfferServiceImpl">       
	</bean>

	    <bean id="myFlight" class="com.mycompany.flights.AthensFlight">    
		<constructor-arg ref="myDailyOfferService" />
		</bean>

	    <bean id="flightPassenger" class="com.mycompany.flights.Passenger">
		    
		<constructor-arg value="50" />
		    
		<constructor-arg value="Michail" />
		    
		<constructor-arg value="True" />
		</bean>
	    
</beans>

	

Output

Δωρεάν Μαθήματα και Σεμινάρια Spring Framework

Για να λύσουμε ένα τέτοιο πρόβλημα, θα μπορούσαμε να χρησιμοποιήσουμε μια ακόμα ιδιότητα του constructor-arg που ονομάζεται index. Το documentation για το συγκεκριμένο attribute είναι εδώ:

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html

Δωρεάν Μαθήματα και Σεμινάρια Spring Framework

Με το index μπορούμε να ορίσουμε την σειρά των μεταβλητών όπως θέλουμε, αλλά ο αριθμός index αντιστοιχεί στην θέση που ανήκει η μεταβλητή στον constructor. Ας κρατήσουμε λοιπόν την λάθος σειρά των μεταβλητών και ας προσθέσουμε το index σε κάθε constructor-arg για να ενημερώσουμε το Spring Framework ποια είναι η θέση της κάθε παραμέτρου στον constructor. Η αρίθμηση του index ξεκινάει από το 0.

beans.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http: //www.springframework.org/schema/beans"        
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

	 <bean id="myDailyOfferService" class="com.mycompany.flights.DailyOfferServiceImpl">       
	</bean>

	    <bean id="myFlight" class="com.mycompany.flights.AthensFlight">    
		<constructor-arg ref="myDailyOfferService" />
		</bean>

	    <bean id="flightPassenger" class="com.mycompany.flights.Passenger">
		    
		<constructor-arg value="50" index="1" />
	    
		<constructor-arg value="Michail" index="0" />
	    
		<constructor-arg value="True" index="2" />
		</bean>
	    
</beans>

	

Output


Passenger Name: Michail, Age: 50, is European: true
Your final destination is Athens Greece
You have received 20% discount on your next trip to Athens

	

Με την προσθήκη του index φαίνεται να έχει λυθεί το πρόβλημα της ασάφειας με την σειρά των μεταβλητών. Αυτό μάλιστα θα μας λύσει και το πρόβλημα αν έχουμε δύο ή και περισσότερους constructors στην κλάση μας. Με άλλα λόγια με την χρήση του index το Spring Framework θα επιλέξει τον σωστό constructor. Ας προσθέσουμε έναν ακόμα constructor στην κλάση Passenger και ας τρέξουμε το πρόγραμμα μας.

Passenger.java


package com.mycompany.flights;

public class Passenger {
    private String passengerName;
    private int passengerAge;
    private boolean european;
    private String identity;

    public Passenger(String passengerName, int passengerAge, String identity) {
        this.passengerName = passengerName;
        this.passengerAge = passengerAge;
        this.identity = identity;
    }

    public Passenger(String passengerName, String identity, int passengerAge) {
        this.passengerName = passengerName;
        this.passengerAge = passengerAge;
        this.identity = identity;
    }

    public String toString(){
        return "Passenger Name: " + this.passengerName + ", Age: " + this.passengerAge
            +", Identity or Password: " +this.identity;
    }
}

	

beans.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http: //www.springframework.org/schema/beans"        
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

	 <bean id="myDailyOfferService" class="com.mycompany.flights.DailyOfferServiceImpl">       
	</bean>

	    <bean id="myFlight" class="com.mycompany.flights.AthensFlight">    
		<constructor-arg ref="myDailyOfferService" />
		</bean>

	    <bean id="flightPassenger" class="com.mycompany.flights.Passenger">
		    
		<constructor-arg value="50" index="1" />
	    
		<constructor-arg value="Michail" index="0" />
	    
		<constructor-arg value="True" index="2" />
		</bean>
	    
</beans>

	

Output


Passenger Name: Michail, Age: 50, Identity or Password: 12345678
Your final destination is Athens Greece
You have received 20% discount on your next trip to Athens

	

Αν αφαιρέσουμε τώρα το index από όλα τα constructor-arg, το πρόγραμμα μας δεν θα μας εμφανίσει κάποιο λάθος γιατί πολύ απλά το Spring Framework θα επιλέξει τον λάθος constructor για την δημιουργία του αντικειμένου!!!.

beans.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http: //www.springframework.org/schema/beans"        
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

	 <bean id="myDailyOfferService" class="com.mycompany.flights.DailyOfferServiceImpl">       
	</bean>

	    <bean id="myFlight" class="com.mycompany.flights.AthensFlight">    
		<constructor-arg ref="myDailyOfferService" />
		</bean>

	    <bean id="flightPassenger" class="com.mycompany.flights.Passenger">
		    
		<constructor-arg value="Michail"  />
    
		<constructor-arg value="12345678"  />
    
		<constructor-arg value="50"  />
		</bean>
	    
</beans>

	

Output


Passenger Name: Michail, Age: 12345678, Identity or Password: 50
Your final destination is Athens Greece
You have received 20% discount on your next trip to Athens

	

Αν δεν θέλετε να χρησιμοποιήσετε index, που έτσι και αλλιώς απαιτεί γνώση της σειράς των μεταβλητών στον constructor, μπορούμε να λύσουμε αυτό το πρόβλημα δηλώνοντας το type της κάθε τιμής που περνάμε στον constructor-arg.

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html

Δωρεάν Μαθήματα και Σεμινάρια Spring Framework

Ας αλλάξουμε το beans.xml ακόμα μια φορά προσθέτοντας το data type των τιμών.

beans.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http: //www.springframework.org/schema/beans"        
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

	 <bean id="myDailyOfferService" class="com.mycompany.flights.DailyOfferServiceImpl">       
	</bean>

	    <bean id="myFlight" class="com.mycompany.flights.AthensFlight">    
		<constructor-arg ref="myDailyOfferService" />
		</bean>

	    <bean id="flightPassenger" class="com.mycompany.flights.Passenger">
		    
		<constructor-arg value="Michail" type="java.lang.String"  />
	    
		<constructor-arg value="12345678" type="java.lang.String"  />
	    
		<constructor-arg value="50" type="int"  />
		</bean>
	    
</beans>

	

Output


Passenger Name: Michail, Age: 50, Identity or Password: 12345678
Your final destination is Athens Greece
You have received 20% discount on your next trip to Athens