j2ee| programming
Summary
Java EE programming is becoming more and more complex. Java EE has developed into a complex network of APIs, complicated programming and configuration. In response to this complexity, new frameworks and methodologies are emerging. These frameworks are highly dependent on a concept known as the IOC (inversion of control, reverse controls). This article explores some of the features and benefits of this approach, as it is related to Java-EE programming and makes it easier to program Java EE.
Brief introduction
Mark Twain's word is often quoted: "... The story about my death is an exaggeration. "There has been a lot of about. NET rumors, as well as the complexity of Java EE API can not be overcome and EJB as a component architecture is about to perish of the pop Geek (geek) culture. It's no big deal from an academic or just an imaginary standpoint, but the fact is that the J2EE/EJB API has undergone a Darwinian evolution. Readers with experience with DCOM or CORBA projects will understand what I mean. In the past, people were happy to hear about the good future of the EJB component model. The reality is that people are investing a lot in all aspects related to the Java EE. It may seem plausible to announce the abandonment of all previous work and to organize it, but it is not based on good business insights. EJB continues to evolve, and terminology, practices, and frameworks emerge (spring up), which make up for the inadequacy of the Java EE API. I'm not talking about spring appearing (UP), right?
I'm a consultant, and my job is to help build large, distributed applications, and usually Java EE applications. Therefore, I have the opportunity to experience the whole life cycle of many projects. In addition, I am able to take what I have just learned from a project that has just been completed and bring it directly into a new project. In a sense, my "natural selection" process has accelerated. I can say that the recent spring (more specifically IOC, or reverse control) has become more and more integrated into my project. In this article, I'll explore spring from the perspective of supporting or enhancing the Java EE project. More precisely, the spring framework can standardize many of the best practices of Java EE, as well as homogenize many ubiquitous Java EE patterns. Next, we'll look at a small part of spring's huge system, focusing on (in my humble opinion) the ability to help improve the functionality of the Java EE application.
Introduction to the IOC
In general, IOC is a technology that manages the association between classes. Yes, it's that simple! No one is isolated, as is the case for each object. Objects in the application are interdependent. It is often tedious and error-prone to express this dependency programmatically. The good IOC framework will be a declarative (through an XML configuration file) rather than programmatic (poor reliability in this way)-to concatenate interdependencies between applications.
The free use of interfaces is one of the main guidelines developed by the IOC. Interface programming greatly enhances the flexibility of the application, thus enhancing declarative association. Interface implementations are declared at runtime by the IOC configuration, which enables the "rebuild (rewire)" Association without affecting or impacting the actual application code. This is a recurring theme in the various IOC frameworks, and is generally a good practice to follow.
A small example
I like to understand concepts faster through examples. Here's a set of examples using the IOC; you'll see that the complexity of these examples is incremental. Most people use their dependency injection (inject dependency) function when they start using the IOC container-that is, declaratively associating an object. Using IOC helps create cleaner code, and it is generally more flexible and easier to rebuild an association between objects if necessary. The merit of the IOC is much more than dependency injection, and its extension is based on the dependency injection program.
We'll start with building simple dependency injection examples. The first example is used to illustrate two concepts already mentioned. The first concept is the ability of the IOC to build and correlate objects at runtime, and the second is the flexibility generated by the combination of interface coding. First, assume that the architect has submitted the UML shown in Figure 1.
Figure 1. Interface pluggable
This small example represents a temperature measurement system. Several sensor objects belong to different types, but they all implement the PROTOCOLADAPTERIFC interface, so they are interchangeable when inserting them into the Temperaturesensor object. When Temperaturesensor is required, an entity in the system must know the specific type of PROTOCOLADAPTERIFC to be generated and associated with the sensor object. In this case, the sensor can be configured based on command-line arguments, rows in the database, or through a property file. This example is not sufficient to create a challenge or to demonstrate a complex framework, but it is sufficient to clarify the IOC Foundation.
But imagine that this happens frequently in a fairly complex application, and you want to change the object association dynamically-at least externally. Suppose there is a dummyprotocoladapter, it always returns the value of 42 and uses it to test. Why not provide a single unified framework? --enables developers to rely on the framework to build associations between classes in a consistent, externally configured manner, and does not cause an abnormal increase in the plant cell class (Factory singleton classe). That may not sound like a big deal, but it relies on the simplicity of the IOC.
We use a Temperaturesensor class, which is associated with a class that implements the PROTOCOLADAPTERIFC interface. Temperaturesensor will use the delegate class to get the temperature value. As the UML diagram shows, there are several classes in an application that implements PROTOCOLADAPTERIFC and can then be used for that association. We will use the IOC framework (spring in this case) to declare the implementation of the PROTOCOLADAPERIFC to be used. Spring will establish an association at run time. Let's take a look at the XML code, which instantiates the Temperaturesensor object and associates a PROTOCOLADAPTERIFC implementation with it. The code looks like this:
After reading the code, the purpose should be very clear. We configure spring to instantiate the Temperaturesensor object and associate it with Rs232adapter as the class that implements the PROTOCOLADAPTERIFC interface. To change an implementation that is already associated with a temperaturesensor, the only thing that needs to be changed is the class value in the sensor bean tag. As long as the PROTOCOLADAPTERIFC interface is implemented, Temperaturesensor is no longer concerned with what is associated.
It is fairly straightforward to apply this to the application. We must first access the spring framework, point it to the correct configuration file, and then ask Spring for an instance of the Tempsensor object based on the name. The following code is appropriate:
Classpathxmlapplicationcontext Appcontext = new Classpathxmlapplicationcontext ( new string[] {" Simplesensor.xml "}); Beanfactory bf = (beanfactory) appcontext; Temperaturesensor ts = (temperaturesensor) Bf.getbean ("Tempsensor"); SYSTEM.OUT.PRINTLN ("The temp is:" + ts.gettemperature ());
As you can see, the code is not very difficult. The first is to start spring and specify the configuration file to use. The bean is then referenced by name (Tempsensor). Spring uses a mechanism that creates the object and associates it with other objects based on the description of the Simplesensor.xml file. It is used to inject dependencies--in this case, instantiate the Rs232adapter object and associate it with the Temperaturesensor object by passing it as a parameter to the Sensordelegate () method.
In comparison, it is not difficult to accomplish this task using programmatic java. As shown below:
Temperaturesensor ts2 = new Temperaturesensor (); Ts2.setsensordelegate (new Rs232adapter ());
Purists may think that this is actually a better approach. Fewer lines of code, and may be more readable. This is true, but this approach is much less flexible.
You can swap and swap out different implementations of different objects in different layers at will. For example, if a component in the Web tier requires additional functionality from a new business object, you simply associate the business object with the Web-tier object, as in the temperaturesensor example above. It will be "injected" into the Web object to be used at any time.
The ability to reconfigure the structure of an entire application means that you can easily change the data source. For example, either create different profiles for different deployment scenarios, or create more useful, different profiles for test scenarios. The mock object that implements the interface may be injected into the test scenario without injecting the real object. We'll introduce an example of this later.
The example described above may be the simplest form of dependency injection. With the same strategy, we can not only associate different classes, but also install properties in the class. Attributes such as strings, integers, or floating-point numbers can be injected into a class through the spring configuration file as long as they have javabean-style accessors. We can also create objects and install properties or bean references through constructors. Its syntax is only slightly more complex than setting it by property.
All of this is done with a flexible declarative configuration. Without the need to change the code, all the hard tasks of building dependency relationships are done by spring.
spring--Standardized Locator Mode
I have always regarded the service locator pattern as a major component of a good Java EE specification. For those unfamiliar with the term, it can be understood that the typical Java EE application is generally composed of several layers. Typically there is a web layer, a service layer (EJB, JMS, WS, WLS Control), and a database. In general, some methods are included in the Find service required to complete a request. Service Locator mode considers it a good idea to wrap these methods in a factory class that hides the complexity of generating or locating a given service. This reduces the addition of Jndi or other service product code that only causes confusion in the Web-tier operations class. Before spring, this was usually accomplished by a test-proven (tried-and-true) Singleton class. The singleton/locator/factory pattern can be described as:
Figure 2. Sequence diagram of the locator pattern
This is a significant improvement over the increased Jndi lookup code that spreads throughout the Web controller code. It is cleverly hidden in the collaboration classes within the factory. We can use spring to improve this term. In addition, the solution will apply to EJB, Web services, asynchronous JMS calls, and even services based on WLS controls. This variant of the locator pattern implemented by spring takes into account some abstraction and homogeneity between business services. In other words, developers of web controllers can really take care of the kind of services they use, a concept similar to "WLS control" but more general.
The IOC framework greatly improves the utility of this pattern and effectively abolishes complex and special singleton code to implement it. By borrowing the concepts introduced in the previous example, we can actually build a very powerful and ubiquitous service locator pattern without extra code. To this end, there is a simple requirement at the outset that Web operations developers should specialize in those things that implement interfaces. This is basically implemented through EJB programming, but not that the service that the developer of the web operation handles must be implemented through EJBS. They may be just plain Java objects or Web services. The point is that the service program should be written through an interface (so that the implementation can be swapped out), and the runtime configuration can be handled by spring.
Spring is ideal for service locator patterns because it is more or less able to handle different types of objects uniformly. With a little planning and extensive use of the IOC, we are able to handle most objects in a common way, without having to worry about their characteristics (EJB, Pojo, etc.), and will not cause an increase in singleton factory classes. This makes the web-tier programming easier and more flexible.
Let's take a look at an example of how this pattern applies to EJBS. We all know that using EJBS can be the most complex approach, because it takes a lot of work to introduce an active reference to the EJB. Using spring, it is recommended that you extend EJB-specific business interfaces with an EJBS interface. This is done for two purposes: to keep two interfaces automatically synchronized, and to help ensure that business services are interchangeable for non-EJB implementations for testing or scavenging (stubbing). We can use spring's inherent utilities to locate and create EJB instances, while handling all the hard work for us. The corresponding code looks like this:
mybizcomponentyourco.project.biz.MyBizInterface
You can then retrieve the bean and start using it as follows:
Mybizinterface MyService = Bf.getbean ("Mybizserviceref");
This returns an object that spring dynamically creates and wraps the underlying target (in this case, a local EJB instance). This approach is very good because it completely hides the fact that we are dealing with EJBS. We will interact with a proxy object that implements a simple business interface. Spring has already generated this object in a thoughtful and dynamic manner based on the "real" business object. The wrapped object is, of course, the local EJB that spring locates and retrieves references for. In addition, you will notice that this form of code is exactly the same as the previous code used to retrieve the Tempsensor object.
So what if we change our minds and want to implement business components with normal Java objects, or perhaps in a test, we want to replace the heavyweight EJB with a cleared (stubbed) object that returns a "fixed (canned)" response? With IOC and spring, these goals can be easily achieved by changing the spring context file. We simply replace the EJB proxy connection by using something more conventional (as we saw in the first spring example):
Class= "Yourco.project.biz.MyStubbedBizService" >
Notice that I only changed the details of what the spring framework returned, and did not change the bean ID. The final result is that the business object's solution has not changed; it looks exactly the same as before:
Mybizinterface MyService =
Bf.getbean ("Mybizserviceref");
The biggest difference is obviously that the object that implements the business interface is now supported by a normal Java object (POJO) and is just a purged (stubbed) version of the interface. This provides a great convenience for unit testing or for changing the characteristics of business services, but has little impact on client code.
Use spring to standardize exceptions
One of the major contributions of spring is the "templating" block of code. This is most evident in pure JDBC programming. We've all written code that has the following features:
Create a database connection that can be created from a pool.
Constructs a query string and submits it.
Iterates through the results and marshals the data to the domain object.
Handles a large number of exceptions that occur at different stages.
Make sure that you write a finally code block to close the connection.
But the code is more or less "boilerplate" all over the place. This is generally harmful, not only because unwanted code increases, but also because something can be omitted, such as a very important shutdown connection, which could lead to a leak of the data resource pool if it is not implemented.
While I'm sure we've all written this kind of "boilerplate" code many times, the results will be interesting and contrasting with the spring approach and the direct JDBC implementation. The "traditional" JDBC implementation might be as follows:
Connection con = null;try{ String url = "Jdbc://blah.blah.blah;"; con = myDataSource (). getconnection (); Statement stmt = Con.createstatement (); String query = "Select TYPE from sensors"; ResultSet rs = stmt.executequery (query); while (Rs.next ()) { String s = rs.getstring ("TYPE"); Logger.debug (S + " " + N); } catch (SQLException ex) { logger.error ("SQL error!", ex);} finally{ con.close ();}
There are some explanations for this method. First of all, it is effective! There is absolutely no error in the code. It connects to the database and gets the data needed from the ' SENSOR ' table. The basic problem of this method stems from lack of abstraction. In a large application, you must repeatedly cut and paste this code, or at least a similar other situation will occur. The big problem is that it relies on programmers to do what they do. As we all know, no matter what the result of a database operation is, you must close the database with a finally statement. Sometimes we forget to do the things we should do. I feel the same guilt as everyone else!
It would be very easy to write a small framework to solve this problem. I believe we have all done this, but why don't we let Spring help us deal with this problem? I'm not sure I can come up with a cleaner, more elegant solution. Let's see how the Spring framework handles this boilerplate JDBC scenario.
Spring supports a wide variety of JDBC, Hibernate, JDO, and Ibatis templates. The template takes a boilerplate concept and converts it to a legitimate programming term. For example, the following code fragment encapsulates each of the steps listed above:
DataSource ds = (DataSource) bf.getbean ("myDataSource"); JdbcTemplate temp = new JdbcTemplate (DS); List sensorlist = Temp.query (' Select sensor.type from sensors ', new RowMapper () {public Object Maprow (ResultSet RS, int rownum) throws SQLException; return rs.getstring (1); } });
This short code eliminates the verbosity of JDBC programming and represents the idea of the model mentioned earlier. Notice that we used the spring's IOC to find the data source for the query. Spring also supports the use of unchecked exceptions for checked exceptions, so many of the checked JDBC exceptions are mapped back to the normally more useful and friendlier hierarchy of unchecked exceptions. Configuring the data source in spring's context file is similar to the following code:
org.gjt.mm.mysql.Driverjdbc:mysql ://romulus/sensorsheaterhotshot
In this case, we used the Apache Commons Toolbox to configure a basic data source. But it's not that we can only use it. We can change the configuration and use the data source that is configured and loaded in Jndi. Spring provides a number of utilities and IOC features to configure and return objects stored in Jndi. For example, if you want to configure and use a data source that is associated with a Jndi context, you can replace the previous data source configuration by entering the following code:
connectionfactory
This code highlights the test flexibility that spring provides for tables. The code can be run in "container" (looking for a data source from Jndi) and can be run outside of the container after minor changes.
While the templating mechanism applies only to certain situations, we can generalize the concept and apply it to a wider context. For example, a mechanism that converts checked exceptions to unchecked exceptions and, in addition, provides some intermediate or unified exception handling policies for exception handling can be helpful. We can also use this mechanism to "soften" the underlying basic anomalies more satisfactorily. We can soften the packetframeparityfaultexception to communicationsunreliableexception. The softer anomaly of this remap indicates that the situation may not be so serious and that it is possible to request it again.
Spring already has a mechanism similar to the wrapper EJB invocation (described in the last section), but unfortunately it does not have anything "generic", at least in the sense of exceptional softening. But spring does have a very robust AOP (aspect-oriented programming) framework that we can use to approach this behavior. The following is a well-designed example of this softening application area (admittedly).
Let's take a look at some of the concepts already discussed earlier in this article. In the first section, we introduce a small application based on remote sensors. Let us now continue to explore this example. We'll start with a simple sensor interface with the following code:
Public interface protocoladapterifc{ the public Integer getremotesensorvalue () throws Commchecksumfault, Commconnectfailure, Commpacketsequencefault;}
There's nothing special about that. It is obvious that anyone implementing the interface will get a remote value and return it to the caller. During this time the caller may have to face some terrible disaster, an example of a checked exception that may be thrown by the interface.
Next we look at an implementation of the interface. The class that implements Protocoladapter is Carrierpigeon, and its code is similar to the following:
public class Carrierpigeon implements protocoladapterifc{ Private Boolean istired = true; Private Boolean canflapwings = false; Public Integer Getremotesensorvalue () throws Commchecksumfault, Commconnectfailure, Commpacketsequencefault { if (istired &&!canflapwings) { throw new Commconnectfailure ("I ' m tired!"); } return new Integer; }
For brevity, the getter and setter methods for attributes are omitted here. When Getremotesensorvalue () is invoked, the Carrierpigeon method checks whether it is overused and whether it can be executed. If it is indeed overused and cannot be executed, we will not get any value and must throw Commconnectionfailure, which is a checked exception. So far, it has been good. But don't get too excited! I have decided not to allow application programmers to respond to "tired pigeons". You can wrap it in an object and catch an exception before you reach it, but you have to deal with 20 different kinds of sensors. In addition, I prefer to deal with these things in a moderately transparent manner, and perhaps change the logic in the exception handler as I learn more about the system. What I want is a compatible API that can be used by application programmers and can be changed or enhanced over time. I want to template exception handling and allow application programmers to handle soft, unchecked exceptions rather than hard exceptions. Spring is very much in line with this situation. The following are the key points of the strategy used for this purpose:
Defines a softer minimum interface for eliminating checked exceptions. This is the interface that the application programmer will use.
Using the Spring AOP architecture, a interceptor is developed between a client invocation and a target object invocation, in this case a "pigeon".
Use spring to install the interceptor and run it.
First look at this softer interface:
Public interface sensorifc{Public Integer getsensorvalue ();}
Note that you can rename the method in a limited scope to make it more meaningful. You can also eliminate checked exceptions, just as you do here. Next, it may be even more interesting that we want spring to inject it into the interceptor of the call stack:
import Org.aopalliance.intercept.methodinterceptor;public class Sensorinvocationinterceptor Implements methodinterceptor{public Object invoke (Methodinvocation invocationtarget) throws Throwable {//Retur N Object Reference object o = null; Convert it to the Protocol interface type PROTOCOLADAPTERIFC PAI = (PROTOCOLADAPTERIFC) invocationtarget.getthi S (); try {o = Pai.getremotesensorvalue (); catch (Commchecksumfault CSF) {throw new Softenedprotocolexception ("protocol error [checksum ERROR]: "+ csf.getmessage ()); catch (Commconnectfailure CF) {throw new Softenedprotocolexception ("protocol error [Comm failure]:" + cf.getmessage ()); catch (Commpacketsequencefault psf) {throw new Softenedprotocolexception ("protocol error [Message SE Quence ERROR] "+ psf.getmessage ()); return o; }}
By implementing the spring Methodinterceptor interface and inserting the class into the spring system (which we'll discuss later), we'll get the actual target method through the Methodinvocation parameter. So that we can extract the real objects we want. Keep in mind that we have changed the interface that the caller sees as SENSORIFC, which enables the target object to implement PROTOCOLADAPTERIFC. We do this to simplify the call, and to eliminate all the checked exceptions. The interceptor invokes only the target method used to catch any checked exceptions that may be thrown and to repackage them with softenedprotocolexception. In fact, we only repackage the message, but we have to be aware of it. Softenedprotocolexception extends the runtimeexception, which is no doubt an unchecked exception. The end result of this operation is that the application developer does not have to handle any checked exceptions. If they really want to handle exceptions, they only need to (not force) handle one: Softenedprotocolexception. That's good!
So how do you get spring to do all of this? The answer is to have the correct configuration file. Let's take a look at the configuration file and see how it works:
sensorinterceptor
When we look at the code in sections, we can see that it's a little bit more complicated than the spring configuration file we saw earlier. The first section of the target object annotation specifies the class to be the target object of the call. Remember that the interceptor passed a parameter to it to represent the target object? That's how it works. Based on this argument, spring now knows which object to pass in. The Code section under "Interceptor" is the class that is invoked before the target method. At this point, if the target class throws a checked exception, start handling the exception and soften it. Spring associates it with the target class. The last section is a link between the various elements. The bean the user is requesting is under the Bean key Temperaturesensorone. Proxyfactorybean will generate and return a proxy class to implement the YOURCO.PROJECT.INTERFACES.SENSORIFC interface. The target object is of course the Protocoladapter Bean, which is supported by an instance of Yourco.project.comm.CarrierPigeon. As long as the user invokes the proxy method, the interceptor that is inserted and invoked is under the bean key Sensorinterceptor and supported by Yourco.project.springsupport.SensorInvocationInterceptor. Note that multiple interceptors are available because the property is a list, so many interceptor objects can be associated with the method call, which is a very useful idea.
When we run the application, we can see some interesting behavior based on the Carrierpigeon value of the insertion. If our carrierpigeon is not overused and can be executed, we will see this output:
The sensor says the temp is:42
Apparently "homing pigeons" are fine and in good condition, and the temperature is calculated at 42. If the "pigeon" is overused or cannot be performed due to changes to the values in the Carrierpigeon Spring section, we will get the results shown below:
Yourco.project.exceptions.comm.SoftenedProtocolException:protocol Error [comm failure]: I ' m tired! At Yourco.project.springsupport.SensorInvocationInterceptor.invoke (sensorinvocationinterceptor.java:57) at Org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (reflectivemethodinvocation.java:144) At Org.springframework.aop.framework.JdkDynamicAopProxy.invoke (jdkdynamicaopproxy.java:174) at . Getsensorvalue (Unknown Source) at Yourco.project.main.Main.main (main.java:32)
In this case, the "pigeon" is either overused or cannot be executed, so the result is softprotocolexception, with a message stating what happened: "I ' m tired!" That's pretty cool!
I want people to begin to understand the power of spring and its many features. The spring framework quietly sprang up and became the real "Swiss Army Knife" in the developer's programming toolbox. Spring is doing well in implementing the legendary promise of enabling developers to concentrate on the basic components of an application, which is the business logic that makes it a great way to go. Spring frees you from some of the intricacies of Java EE. Spring is powerful because it makes most things look like very ordinary Java objects, regardless of their nature or source. Now that spring is shouldering the burden of creating, associating, and configuring, the developer is simply mastering the method of using an object rather than constructing it. Spring is like a cooked meal purchased at a grocery store. All you have to do is decide what you want to eat, take it home, heat it, and eat it!
Comprehensive description
Spring is a very robust lightweight framework that makes up for the J2EE/EJB environment in a very good way. The real greatness of spring is that it does not go to extremes. You can start using spring in a very simple way (as I did), just building common associations as an implementation of the locator pattern. Later on, you'll discover its amazing functionality, and it will soon require more and more of it.
One of the amazing places I've found is the test flexibility that spring offers. There is now increasing emphasis on unit testing through JUnit, which increases testing rather than reducing it. The use of Java-EE containers makes testing extremely complex and difficult to carry out. This dilemma arises from the coupling between business logic and container framework services. With the help of spring's configuration mechanism, the implementation can be switched dynamically, which helps to release business objects from the container. As we have seen, if you only want to test the Web component, changing the active EJB to its agent or to a purged business service does not cause much impact. With JDBC or Hibernate data Access objects, we can test these components using common simple JDBC, non-XA data source connections, and replace them seamlessly with robust, JTA, Jndi-based corresponding connections. The conclusion is that if the code is easy to test and therefore tested more, the quality is bound to improve.
Conclusion
This article provides a rough overview of the IOC and introduces spring in detail. The spring framework has many features, many of which are just a few of the features in this article. From basic dependency injection to complex AOP operations, these form the power of spring, which is one of its main advantages. Being able to use a more or less IOC function based on the problem is an attractive idea, which I think is also popular in the often convoluted Java programming world. Now that I have read this article, I sincerely hope that it will help you and apply to your work. Please feel free to provide feedback!