Developing an IOC-Container for Dependency Injection Part II
Part I | Part II | Part III
Welcome to the second part. Today we want to define how our configuration file shall look and start with the implementation of our container.
Look at the config-file of my personal dreams:
We call every injected class a service. For every service we provide a implementation class. A service can have properties. We don't want to be too extreme in the beginning, so we just want Strings, lists, arrays , maps and references to other classes (via).
The Details for the configfile above:
Here we define a Bean for the concrete class ioc.example.Customer and mark it with the id Customer. We define some Properties for that Bean:
id is a property that we initialize with the value 1. The container should automatically set the correct type for every primitive. The second property, names, is a list that we initialize with the values 12, 15, 16. It should also be possible to use arrays (for the beginning they'll be automatically String[]) and maps, as you can see at the properties numbers and smallmap. Now to the interesting stuff: The properties User and Admin are referenced beans, defined below in the same file. the Container must take care of all the Dependency Injection Stuff.
As you can see, it shouldn't matter wether you are using a simple concrete class for injection or an implementation of an interface (UserImpl).
So how can we implement the container? First we define the Interface:
What are we doing here? We need methods to retrieve the auto-wired objects. And we want to have the ability to get them via the name (the id) or the class/class name.
Here comes the Implementation of the Standard IOC Container:
Lets dive into the details:
First, in line 12, we read an configuration xml (like the one above) and parse throught it with an IOCConfigParser class. Here we receive an presentation of our services. Maybe thats not necessary, but that way we can put the configuration in a state and fill it with information that makes it easier to create the "real" services afterwards.
At line 15 we use an IOCServiceFactory class to create all services. That means instantiation of the correct classes, filling them with startup values with correct types defined in the config-file and wiring them together. And this means lots of reflection of course ;-) The services (or the beans, pojos, objects, whatever) are stored as a map in an instance variable. The other methods just give the corresponding service to the caller.
But that should be enough for today. In part 3 we dive deeper and look whats behind the IOCContainer, the Factory and so on. Stay tuned.
Welcome to the second part. Today we want to define how our configuration file shall look and start with the implementation of our container.
Look at the config-file of my personal dreams:
<services>
<service name="Customer" class="ioc.example.Customer">
<property name="id" value="1">
<property name="names" type="list" value="[12,15,16]">
<property name="numbers" type="array" value="[a,b,c]">
<property name="smallmap" type="map" value="[1:a,2:b,3:c]">
<property reference="User">
<property reference="Admin">
</property>
<service name="User" class="ioc.example.UserImpl">
<service name="Admin" class="ioc.example.Admin">
<property name="adminName" value="Sam">
</property>
</service>
We call every injected class a service. For every service we provide a implementation class. A service can have properties. We don't want to be too extreme in the beginning, so we just want Strings, lists, arrays , maps and references to other classes (via
The Details for the configfile above:
Here we define a Bean for the concrete class ioc.example.Customer and mark it with the id Customer. We define some Properties for that Bean:
id is a property that we initialize with the value 1. The container should automatically set the correct type for every primitive. The second property, names, is a list that we initialize with the values 12, 15, 16. It should also be possible to use arrays (for the beginning they'll be automatically String[]) and maps, as you can see at the properties numbers and smallmap. Now to the interesting stuff: The properties User and Admin are referenced beans, defined below in the same file. the Container must take care of all the Dependency Injection Stuff.
As you can see, it shouldn't matter wether you are using a simple concrete class for injection or an implementation of an interface (UserImpl).
So how can we implement the container? First we define the Interface:
package ioc.container;
public interface IOCContainer {
public Object getInstance(String id);
public Object getInstanceByClass(String clazz);
public Object getInstanceByClass(Class clazz);
}
What are we doing here? We need methods to retrieve the auto-wired objects. And we want to have the ability to get them via the name (the id) or the class/class name.
Here comes the Implementation of the Standard IOC Container:
01 /**
02 * Standard Implementation for the IOCContainer
03 */
04 public class IOCContainerStandardImpl implements IOCContainer {
05
06 Map services;
07 IOCConfig conf;
08
09 public IOCContainerStandardImpl(String config) {
10
11 //Read Configuration-XML
12 conf = new IOCConfigParser().parse(config);
13
14 //Create all Services
15 services = new IOCServiceFactory().createServices(conf);
16 }
17
18 /**
19 * Create an Instance with the
20 * id of this class
21 */
22 public Object getInstance(String id) {
23 return services.get(id);
24 }
25
26 /**
27 * Create an Instance with the class
28 */
29 public Object getInstanceByClass(Class clazz) {
30 return services.get(clazz.getName());
31 }
32
33 /**
34 * Create an Instance with the fully
35 * qualified name of the class
36 *
37 * @param clazz
38 * @return
39 */
40 public Object getInstanceByClass(String clazz) {
41 return services.get(clazz);
42 }
43 }
Lets dive into the details:
First, in line 12, we read an configuration xml (like the one above) and parse throught it with an IOCConfigParser class. Here we receive an presentation of our services. Maybe thats not necessary, but that way we can put the configuration in a state and fill it with information that makes it easier to create the "real" services afterwards.
At line 15 we use an IOCServiceFactory class to create all services. That means instantiation of the correct classes, filling them with startup values with correct types defined in the config-file and wiring them together. And this means lots of reflection of course ;-) The services (or the beans, pojos, objects, whatever) are stored as a map in an instance variable. The other methods just give the corresponding service to the caller.
But that should be enough for today. In part 3 we dive deeper and look whats behind the IOCContainer, the Factory and so on. Stay tuned.
add to del.icio.us
submit to reddit
1 Comments:
At 4:56 PM,
Anonymous said…
That's a great story. Waiting for more. Pilates fitness workouts Adult flash online cartoons Credit report repair kit online gambling Hidden teen sex videos sampras tennis car rental savaria wheelchair lift Infiniti sedan concept General filter 1040 humidifier manual Leadership management training minneapolis
Post a Comment
Links to this post:
Create a Link
<< Home