A cool song by Fort Minor - a member of Linkin Park. I like this song very much. Hope you'll like it too. 来自LinkinPark成员FortMinor写的一首很酷的歌。我非常喜欢。希望你们也喜欢。 Download link下载链接 Remember The Name - Fort MinorLyric歌词 Remember The Name Fort Minor [Mike - Spoken] You ready? Lets go! Yeah, for those of you that want to know what we're all about It's like this y'all (c'mon!) [Chorus] It's just ten percent luck, Twenty percent skill, Fifteen percent concentrated power of will, Five percent pleasure, Fifty percent pain, And a hundred percent reason to remember the name! [Mike] Mike He doesn't need his name up in lights He just wants to be heard whether it's the beat or the mic He feels so unlike everybody else, alone In spite of the fact that some people still think that they know him But **** em' He knows the code: It's not about the salary It's about reality and making some noise Makin the story Makin sure his clique stays up That means when he puts it down Tak's pickin it up! [Tak] Who the hell is he anyway? He never really talks much Never concerned with status but still leavin them star struck Humbled through opportunities given to him despite the fact That many misjudge him because he makes a livin from writin raps Put it together himself, now the picture connects Never askin for someone's help, to get some respect He's only focused on what he wrote, his will is beyond reach And now when it all unfolds, the skill of an artist [Ryu] It's just twenty percent skill Eighty percent fear Be one hundred percent clear cause Ryu is ill Who would've thought that he'd be the one to set the west in flames And I heard him wreckin with The Crystal Method, "Name Of The Game" Came back dropped Megadef, took em to church I'm like bleach man, why you have the stupidest verse? This dude is the truth, now everybody be givin him guest spots His stock's through the roof I heard he ****in with S-Dot! [Chorus] It's just ten percent luck, Twenty percent skill, Fifteen percent concentrated power of will, Five percent pleasure, Fifty percent pain, And a hundred percent reason to remember the name! [Ryu] They call him Ryu the sick And he's spittin fire with Mike Got him out the dryer he's hot Found him in Fort Minor with Tak Been a ****in annihilist porcupine He's a prick, he's a cock The type woman want to be with And rappers hope he get shot Eight years in the makin Patiently waitin to blow Now the record with shinoda's takin over the globe He's got a partner in crime his shit is equally dope You wont believe the kind of shit that comes out of this kid's throat [Tak] Tak He's not your everyday on the block He knows how to work with wood He's god makin his way to the top People think its a common owners name People keep askin him was it given at birth, Or does it stand for an acronym? No he's livin proof, Got him rockin the booth He'll get you buzzin quicker than a shot of vodka with juice Him and his crew are known around as one of the best Dedicated to what they doin give a 100% [Mike] Forget Mike Nobody really knows how or why he works so hard It seems like he's never got time Because he writes every note and he writes every line And I've seen him at work when that light goes on in his mind It's like a design is written in his head every time Before he even touches a key or speaks in a rhyme And those mother****ers he runs with, those kids that he signed? Ridiculous, without even trying, how do they do it?! [Chorus] It's just ten percent luck, Twenty percent skill, Fifteen percent concentrated power of will, Five percent pleasure, Fifty percent pain, And a hundred percent reason to remember the name! x2 [Outro - Mike] Yeah! Fort Minor! M. Shinoda, Styles of Beyond! Ryu, Tak here! Machine Shop!
The question you should be asking at this point is whether or not a knight should be responsible for obtaining a quest. Or, should a knight be given a quest to embark upon?
Consider the following change to KnightOfTheRoundTable:
public class KnightOfTheRoundTable implements Knight {
private Quest quest;
...
public KnightOfTheRoundTable(String name) {
...
}
public HolyGrail embarkOnQuest() throws QuestException {
...
return quest.embark();
}
public void setQuest(Quest quest) {
this.quest = quest;
}
}
Notice the difference? Compare figure 1.3 with figure 1.2 to see the difference in how a knight obtains its quest. Now the knight is given a quest instead of retrieving one itself. KnightOfTheRoundTable is no longer responsible for retrieving its own quests. And because it only knows about a quest through the Quest interface, you could give a knight any implementation of Quest you want. In a production system, maybe you would give it a HolyGrailQuest, but in a test case you would give it a mock implementation of Quest.
In a nutshell, that is what inversion of control is all about: the responsibility of coordinating collaboration between dependent objects is transferred away from the objects themselves. And that's where lightweight container frameworks, such as Spring, come into play.
Assigning a quest to a knight
Now that you've written your KnightOfTheRoundTable class to be given any arbitrary Quest object, how can you specify which Quest it should be given?
Figure 1.3 A knight is given a quest through its setQuest() method.
The act of creating associations between application components is referred to as wiring. In Spring, there are many ways to wire components together, but the most common approach is via XML. Listing 1.8 shows a simple Spring configuration file, knight.xml, that gives a quest (specifically, a HolyGrailQuest) to a KnightOfTheRoundTable.
Listing 1.8 Wiring a quest to a knight in knight.xml
Click here for a larger image.
This is just a simple approach to wiring beans. Don't worry too much about the details of it right now. In chapter 2 we'll explain more about what is going on here, as well as show you even more ways you can wire your beans in Spring.
Now that we've declared the relationship between a knight and a quest, we need to load up the XML file and kick off the application.
Seeing it work
In a Spring application, a BeanFactory loads the bean definitions and wires the beans together. Because the beans in the knight example are declared in an XML file, an XmlBeanFactory is the appropriate factory for this example. The main() method in listing 1.9 uses an XmlBeanFactory to load knight.xml and to get a reference to the "knight" object.
Listing 1.9 Running the knight example
Click here for a larger image.
Once the application has a reference to the KnightOfTheRoundTable object, it simply calls the embarkOnQuest() method to kick off the knight's adventure. Notice that this class knows nothing about the quest the knight will take. Again, the only thing that knows which type of quest will be given to the knight is the knight.xml file.
It's been a lot of fun sending knights on quests using inversion of control, but now let's see how you can use IoC in your real-world enterprise applications.4
1.4.3 IoC in enterprise applications
Suppose that you've been tasked with writing an online shopping application. Included in the application is an OrderServiceBean, implemented as a stateless session bean. Now you want to have a class that creates an Order object from user input (likely an HTML form) and call the createOrder() method on your OrderServiceBean, as shown in listing 1.10.
Listing 1.10 Creating an order using EJB
Click here for a larger image.
Notice that it took five lines of code just to get your OrderService object. Now imagine having to do this everywhere you need an OrderService object. Now imagine you have ten other EJBs in your application. That is a lot of code! But duplicating this code everywhere would be ridiculous, so a ServiceLocator is typically used instead. A ServiceLocator acts as a central point for obtaining and caching EJBHome references:
private OrderService getOrderService() {
OrderServiceHome home =
ServiceLocator.locate(OrderServiceHome);
OrderService orderService = home.create();
}
While this removes the need to duplicate the lookup code everywhere in the application, one problem still remains: we always have to explicitly look up our services in our code.
Now let's see how this would be implemented in Spring:
private OrderService orderService;
public void doRequest(HttpServletRequest request) {
Order order = createOrder(request);
orderService.createOrder(order);
}
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
No lookup code! The reference to OrderService is given to our class by the Spring container through the setOrderService() method. With Spring, we never have to trouble ourselves with fetching our dependencies. Instead, our code can focus on the task at hand.
But inversion of control is only one of the techniques that Spring offers to JavaBeans. There's another side to Spring that makes it a viable framework for enterprise development. Let's take a quick look at Spring's support for aspect-oriented programming.
End Notes
1 In this book, Spring was originally called "interface21."
2 The container actually performs other activities involving the life cycle of the bean. But for illustrative purposes, these two lines are sufficient.
3 Although we agree that "dependency injection" is a more accurate name than "inversion of control," we're likely to use both terms interchangeably in this book.
4 This assumes that your real-world applications do not involve knights and quests. In the event that your current project does involve knights and quests, you may disregard the next section.
More to Come
|
The rest of this sample chapter will appear on our Web site starting April 27th. |
About the Authors
Craig Walls is a software developer with over 10 years' experience and co-author of XDoclet in Action. He has sucessfully implemented a number of Spring applications. Craig lives in Denton, Texas.
An avid supporter of open source Java technologies, Ryan Breidenbach has been developing Java web applications for the past five years. He lives in Coppell, Texas.
About the Book
Spring in Action by Craig Walls and Ryan Breidenbach
Published February 2005, Softbound, 472 pages Published by Manning Publications Co. ISBN 1932394354 Retail price: $44.95 Ebook price: $22.50. To purchase the ebook go to http://www.manning.com/walls2. This material is from Chapter 1 of the book.
By Craig Walls and Ryan BreidenbachThe BeanFactory class used here is the Spring container. After loading the hello.xml file into the container, the main() method calls the getBean() method on the BeanFactory to retrieve a reference to the greeting service. With this reference in hand, it finally calls the sayGreeting() method. When we run the Hello application, it prints (not surprisingly) Buenos Dias! This is about as simple a Spring-enabled application as we can come up with. But it does illustrate the basics of configuring and using a class in Spring. Unfortunately, it is perhaps too simple because it only illustrates how to configure a bean by injecting a String value into a property. The real power of Spring lies in how beans can be injected into other beans using IoC. 1.4 Understanding inversion of controlInversion of control is at the heart of the Spring framework. It may sound a bit intimidating, conjuring up notions of a complex programming technique or design pattern. But as it turns out, IoC is not nearly as complex as it sounds. In fact, by applying IoC in your projects, you'll find that your code will become significantly simpler, easier to understand, and easier to test. But what does "inversion of control" mean? 1.4.1 Injecting dependenciesIn an article written in early 2004, Martin Fowler asked what aspect of control is being inverted. He concluded that it is the acquisition of dependent objects that is being inverted. Based on that revelation, he coined a better name for inversion of control: dependency injection.3 Any nontrivial application (pretty much anything more complex than HelloWorld.java) is made up of two or more classes that collaborate with each other to perform some business logic. Traditionally, each object is responsible for obtaining its own references to the objects it collaborates with (its dependencies). As you'll see, this can lead to highly coupled and hard-to-test code. Applying IoC, objects are given their dependencies at creation time by some external entity that coordinates each object in the system. That is, dependencies are injected into objects. So, IoC means an inversion of responsibility with regard to how an object obtains references to collaborating objects. 1.4.2 IoC in actionIf you're like us, then you're probably anxious to see how this works in code. We aim to please, so without further delay... Suppose that your company's crack marketing team culled together the results of their expert market analysis and research and determined that what your customers need is a knight. That is, they need a Java class that represents a knight. After probing them for requirements, you learn that what they specifically want is for you to implement a class that represents an Arthurian knight of the Round Table that embarks on brave and noble quests to find the Holy Grail. This is an odd request, but you've become accustomed to the strange notions and whims of the marketing team. So, without hesitation, you fire up your favorite IDE and bang out the class in listing 1.5. Listing 1.5 KnightOfTheRoundTable.java In listing 1.5 the knight is given a name as a parameter of its constructor. Its constructor sets the knight's quest by instantiating a HolyGrailQuest. The implementation of HolyGrailQuest is fairly trivial, as shown in listing 1.6. Listing 1.6 HolyGrailQuest.java package com.springinaction.chapter01.knight;
public class HolyGrailQuest {
public HolyGrailQuest() {}
public HolyGrail embark() throws GrailNotFoundException {
HolyGrail grail = null;
// Look for grail
...
return grail;
}
}
Satisfied with your work, you proudly check the code into version control. You want to show it to the marketing team, but deep down something doesn't feel right. You almost dismiss it as the burrito you had for lunch when you realize the problem: you haven't written any unit tests. Knightly testingUnit testing is an important part of development. It not only ensures that each individual unit functions as expected, but it also serves to document each unit in the most accurate way possible. Seeking to rectify your failure to write unit tests, you put together the test case (listing 1.7) for your knight class. Listing 1.7 Testing the KnightOfTheRoundTable package com.springinaction.chapter01.knight;
import junit.framework.TestCase;
public class KnightOfTheRoundTableTest extends TestCase {
public void testEmbarkOnQuest() {
KnightOfTheRoundTable knight =
new KnightOfTheRoundTable("Bedivere");
try {
HolyGrail grail = knight.embarkOnQuest();
assertNotNull(grail);
assertTrue(grail.isHoly());
} catch (GrailNotFoundException e) {
fail();
}
}
}
After writing this test case, you set out to write a test case for HolyGrailQuest. But before you even get started, you realize that the KnightOfTheRoundTableTest test case indirectly tests HolyGrailQuest. You also wonder if you are testing all contingencies. What would happen if HolyGrailQuest's embark() method returned null? Or what if it were to throw a GrailNotFoundException? Who's calling who?The main problem so far with KnightOfTheRoundTable is with how it obtains a HolyGrailQuest. Whether it is instantiating a new HolyGrail instance or obtaining one via JNDI, each knight is responsible for getting its own quest (as shown in figure 1.2). Therefore, there is no way to test the knight class in isolation. As it stands, every time you test KnightOfTheRoundTable, you will also indirectly test HolyGrailQuest.
Figure 1.2 A knight is responsible for getting its own quest, through instantiation or some other means. What's more, you have no way of telling HolyGrailQuest to behave differently (e.g., return null or throw a GrailNotFoundException) for different tests. What would help is if you could create a mock implementation of HolyGrailQuest that lets you decide how it behaves. But even if you were to create a mock implementation, KnightOfTheRoundTable still retrieves its own HolyGrailQuest, meaning you would have to make a change to KnightOfTheRoundTable to retrieve the mock quest for testing purposes (and then change it back for production). Decoupling with interfacesThe problem, in a word, is coupling. At this point, KnightOfTheRoundTable is statically coupled to HolyGrailQuest. They're handcuffed together in such a way that you can't have a KnightOfTheRoundTable without also having a HolyGrailQuest. Coupling is a two-headed beast. On one hand, tightly coupled code is difficult to test, difficult to reuse, difficult to understand, and typically exhibits "whack-a-mole" bugs (i.e., fixing one bug results in the creation of one or more new bugs). On the other hand, completely uncoupled code doesn't do anything. In order to do anything useful, classes need to know about each other somehow. Coupling is necessary, but it should be managed very carefully. A common technique used to reduce coupling is to hide implementation details behind interfaces so that the actual implementation class can be swapped out without impacting the client class. For example, suppose you were to create a Quest interface: package com.springinaction.chapter01.knight;
public interface Quest {
public abstract Object embark() throws QuestException;
}
Then, you change HolyGrailQuest to implement this interface. Also, notice that embark now returns an Object and throws a QuestException. package com.springinaction.chapter01.knight;
public class HolyGrailQuest implements Quest {
public HolyGrailQuest() {}
public Object embark() throws QuestException {
// Do whatever it means to embark on a quest
return new HolyGrail();
}
}
Also, the following method must also change in KnightOfTheRoundTable to be compatible with these Quest types: private Quest quest;
...
public Object embarkOnQuest() throws QuestException {
return quest.embark();
}
Likewise, you could also have KnightOfTheRoundTable implement the following Knight interface: public interface Knight {
public Object embarkOnQuest() throws QuestException;
}
Hiding your class's implementation behind interfaces is certainly a step in the right direction. But where many developers fall short is in how they retrieve a Quest instance. For example, consider this possible change to KnightOfTheRoundTable: public class KnightOfTheRoundTable implements Knight {
private Quest quest;
...
public KnightOfTheRoundTable(String name) {
quest = new HolyGrailQuest();
...
}
public Object embarkOnQuest() throws QuestException {
return quest.embark();
}
}
Here the KnightOfTheRoundTable class embarks on a quest through the Quest interface. But, the knight still retrieves a specific type of Quest (here a HolyGrailQuest). This isn't much better than before. A KnightOfTheRoundTable is stuck going only on quests for the Holy Grail and no other types of quest.
The core module's BeanFactory makes Spring a container, but the context module is what makes it a framework. This module extends the concept of BeanFactory, adding support for internationalization (I18N) messages, application life cycle events, and validation.
In addition, this module supplies many enterprise services such as e-mail, JNDI access, EJB integration, remoting, and scheduling. Also included is support for integration with templating frameworks such as Velocity and FreeMarker.
Spring's AOP module
Spring provides rich support for aspect-oriented programming in its AOP module. This module serves as the basis for developing your own aspects for your Spring-enabled application.
To ensure interoperability between Spring and other AOP frameworks, much of Spring's AOP support is based on the API defined by the AOP Alliance. The AOP Alliance is an open-source project whose goal is to promote adoption of AOP and interoperability among different AOP implementations by defining a common set of interfaces and components. You can find out more about the AOP Alliance by visiting their website at http://aopalliance.sourceforge.net.
The Spring AOP module also introduces metadata programming to Spring. Using Spring's metadata support, you are able to add annotations to your source code that instruct Spring on where and how to apply aspects.
JDBC abstraction and the DAO module
Working with JDBC often results in a lot of boilerplate code that gets a connection, creates a statement, processes a result set, and then closes the connection. Spring's JDBC and Data Access Objects (DAO) module abstracts away the boilerplate code so that you can keep your database code clean and simple, and prevents problems that result from a failure to close database resources. This module also builds a layer of meaningful exceptions on top of the error messages given by several database servers. No more trying to decipher cryptic and proprietary SQL error messages!
In addition, this module uses Spring's AOP module to provide transaction management services for objects in a Spring application.
Object/relational mapping integration module
For those who prefer using an object/relational mapping (ORM) tool over straight JDBC, Spring provides the ORM module. Spring doesn't attempt to implement its own ORM solution, but does provide hooks into several popular ORM frameworks, including Hibernate, JDO, and iBATIS SQL Maps. Spring's transaction management supports each of these ORM frameworks as well as JDBC.
Spring's web module
The web context module builds on the application context module, providing a context that is appropriate for web-based applications. In addition, this module contains support for several web-oriented tasks such as transparently handling multipart requests for file uploads and programmatic binding of request parameters to your business objects. It also cotains integration support with Jakarta Struts.
The Spring MVC framework
Spring comes with a full-featured Model/View/Controller (MVC) framework for building web applications. Although Spring can easily be integrated with other MVC frameworks, such as Struts, Spring's MVC framework uses IoC to provide for a clean separation of controller logic from business objects. It also allows you to declaratively bind request parameters to your business objects, What's more, Spring's MVC framework can take advantage of any of Spring's other services, such as I18N messaging and validation.
Now that you know what Spring is all about, let's jump right into writing Spring applications, starting with the simplest possible example that we could come up with.
1.3 Spring jump start
In the grand tradition of programming books, we'll start by showing you how Spring works with the proverbial "Hello World" example. Unlike the original Hello World program, however, our example will be modified a bit to demonstrate the basics of Spring.
Note: To find out how to download Spring and plug it into your project's build routine, refer to appendix A.
Spring-enabled applications are like any Java application. They are made up of several classes, each performing a specific purpose within the application. What makes Spring-enabled applications different, however, is how these classes are configured and introduced to each other. Typically, a Spring application has an XML file that describes how to configure the classes, known as the Spring configuration file.
The first class that our Springified Hello World example needs is a service class whose purpose is to print the infamous greeting. Listing 1.1 shows GreetingService.java, an interface that defines the contract for our service class.
Listing 1.1 The GreetingService interface separates the service's implementation from its interface.
package com.springinaction.chapter01.hello;
public interface GreetingService {
public void sayGreeting();
}
GreetingServiceImpl.java (listing 1.2) implements the GreetingService interface. Although it's not necessary to hide the implementation behind an interface, it's highly recommended as a way to separate the implementation from its contract.
Listing 1.2 GreetingServiceImpl.java: Responsible for printing the greeting
package com.springinaction.chapter01.hello;
public class GreetingServiceImpl implements GreetingService {
private String greeting;
public GreetingServiceImpl() {}
public GreetingServiceImpl(String greeting) {
this.greeting = greeting;
}
public void sayGreeting() {
System.out.println(greeting);
}
public void setGreeting(String greeting) {
this.greeting = greeting;
}
}
The GreetingServiceImpl class has a single property: the greeting property. This property is simply a String that holds the text that is the message that will be printed when the sayGreeting() method is called. You may have noticed that the greeting can be set in two different ways: by the constructor or by the property's setter method.
What's not apparent just yet is who will make the call to either the constructor or the setGreeting() method to set the property. As it turns out, we're going to let the Spring container set the greeting property. The Spring configuration file (hello.xml) in listing 1.3 tells the container how to configure the greeting service.
Listing 1.3 Configuring Hello World in Spring
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="greetingService"
class="com.springinaction.chapter01.hello.GreetingServiceImpl">
<property name="greeting">
<value>Buenos Dias!</value>
</property>
</bean>
</beans>
The XML file in listing 1.3 declares an instance of a GreetingServiceImpl in the Spring container and configures its greeting property with a value of "Buenos Dias!" Let's dig into the details of this XML file a bit to understand how it works.
At the root of this simple XML file is the <beans> element, which is the root element of any Spring configuration file. The <bean> element is used to tell the Spring container about a class and how it should be configured. Here, the id attribute is used to name the bean greetingService and the class attribute specifies the bean's fully qualified class name.
Within the <bean> element, the <property> element is used to set a property, in this case the greeting property. By using <property>, we're telling the Spring container to call setGreeting() when setting the property.
The value of the greeting is defined within the <value> element. Here we've given the example a Spanish flair by choosing "Buenos Dias" instead of the traditional "Hello World."
The following snippet of code illustrates roughly what the container does when instantiating the greeting service based on the XML definition in listing 1.3:2
GreetingServiceImpl greetingService = new GreetingServiceImpl();
greetingService.setGreeting("Buenos Dias!");
Similarly, we may choose to have Spring set the greeting property through GreetingServiceImpl's single argument constructor. For example:
<bean id="greetingService"
class="com.springinaction.chapter01.hello.GreetingServiceImpl">
<constructor-arg>
<value>Buenos Dias!</value>
</constructor-arg>
</bean>
The following code illustrates how the container will instantiate the greeting service when using the <constructor-arg> element:
GreetingServiceImpl greetingService =
new GreetingServiceImpl("Buenos Dias");
The last piece of the puzzle is the class that loads the Spring container and uses it to retrieve the greeting service. Listing 1.4 shows this class.
Listing 1.4 The Hello World main class
package com.springinaction.chapter01.hello;
import java.io.FileInputStream;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
public class HelloApp {
public static void main(String[] args) throws Exception {
BeanFactory factory =
new XmlBeanFactory(new FileInputStream("hello.xml"));
GreetingService greetingService =
(GreetingService) factory.getBean("greetingService");
greetingService.sayGreeting();
}
}
By Craig Walls and Ryan BreidenbachIt all started with a bean. In 1996 the Java programming language was still a young, exciting, up-and-coming platform. Many developers flocked to the language because they had seen how to create rich and dynamic web applications using applets. But they soon learned that there was more to this strange new language than animated juggling cartoon characters. Unlike any language before it, Java made it possible to write complex applications made up of discrete parts. They came for the applets, but they stayed for the components. It was in December of that year that Sun Microsystems published the Java-Beans 1.00-A specification. JavaBeans defined a software component model for Java. This specification defined a set of coding policies that enabled simple Java objects to be reusable and easily composed into more complex applications. Although JavaBeans were intended as a general-purpose means of defining reusable application components, they have been primarily used as a model for building user interface widgets. They seemed too simple to be capable of any "real" work. Enterprise developers wanted more. Sophisticated applications often require services such as transaction support, security, and distributed computing—services not directly provided by the Java-Beans specification. Therefore, in March 1998, Sun published the 1.0 version of the Enterprise JavaBeans (EJB) specification. This specification extended the notion of Java components to the server side, providing the much-needed enterprise services, but failed to continue the simplicity of the original JavaBeans specification. In fact, except in name, EJB bears very little resemblance to the original JavaBeans specification. Despite the fact that many successful applications have been built based on EJB, EJB never really achieved its intended purpose: to simplify enterprise application development. Every version of the EJB specification contains the following statement: "Enterprise JavaBeans will make it easy to write applications." It is true that EJB's declarative programming model simplifies many infrastructural aspects of development, such as transactions and security. But EJBs are complicated in a different way by mandating deployment descriptors and plumbing code (home and remote/local interfaces). Over time many developers became disenchanted with EJB. As a result, its popularity has started to wane in recent years, leaving many developers looking for an easier way. Now Java component development is coming full circle. New programming techniques, including aspect-oriented programming (AOP) and inversion of control (IoC), are giving JavaBeans much of the power of EJB. These techniques furnish JavaBeans with a declarative programming model reminiscent of EJB, but without all of EJB's complexity. No longer must you resort to writing an unwieldy EJB component when a simple JavaBean will suffice. And that's where Spring steps into the picture. 1.1 Why Spring?If you are reading this book, you probably want to know why Spring would be good for you. After all, the Java landscape is full of frameworks. What makes Spring any different? To put it simply, Spring makes developing enterprise applications easier. We don't expect that to convince you at face value, so first let's take a look at life without Spring. 1.1.1 A day in the life of a J2EE developerAlex is a Java developer who has just started on his first enterprise application. Like many Java 2 Enterprise Edition (J2EE) applications, it is a web application that serves many users and accesses an enterprise database. In this case, it is a customer management application that will be used by other employees at his company. Eager to get to work, Alex fires up his favorite integrated development environment (IDE) and starts to crank out his first component, the CustomerManager component. In the EJB world, to develop this component Alex actually has to write several classes—the home interface, the local interface, and the bean itself. In addition, he has to create a deployment descriptor for this bean. Seeing that creating each of these files for every bean seems like a lot of effort, Alex incorporates XDoclet into his project. XDoclet is a code generation tool that can generate all of the necessary EJB files from a single source file. Although this adds another step to Alex's development cycle, his coding life is now much simpler. With XDoclet now handling a lot of the grunt work for him, Alex turns his attention to his real problem—what exactly should the CustomerManager component do? He jumps in with its first method, getPreferredCustomer(). There are several business rules that define exactly what a preferred customer is, and Alex dutifully codes them into his CustomerManager bean. Wanting to confirm that his logic is correct, Alex now wants to write some tests to validate his code. But then it occurs to him: the code he is testing will be running within the EJB container. Therefore, his tests need to execute within the container as well. To easily accomplish this, he concocts a servlet that will be responsible for executing these tests. Since all J2EE containers support servlets, this will allow him to execute his tests in the same container as his EJB. Problem solved! So Alex fires up his J2EE container and runs his tests. His tests fail. Alex sees his coding error, fixes it, and runs the tests again. His tests fail again. He sees another error and fixes it. He fires up the container and runs the tests again. As Alex is going through this cycle, he notices something. The fact that he has to start the J2EE container for each batch of testing really slows down his development cycle. The development cycle should go code, test, code, test. This pattern has now been replaced with code, wait, test, code, wait, test, code, wait, get increasingly frustrated... While waiting for the container to start during another test run, Alex thinks, "Why am I using EJB in the first place?" The answer, of course, is because of the services it provides. But Alex isn't using entity beans, so he is not using persistence services. Alex is also not using the remoting or security services. In fact, the only EJB service Alex is going to use is transaction management. This leads Alex to another question: "Is there an easier way?" 1.1.2 Spring's pledgeThe above story was a dramatization based on the current state of J2EE—specifically EJB. In its current state, EJB is complicated. It isn't complicated just to be complicated. It is complicated because EJBs were created to solve complicated things, such as distributed objects and remote transactions. Unfortunately, a good number of enterprise projects do not have this level of complexity but still take on EJB's burden of multiple Java files and deployment descriptors and heavyweight containers. With EJB, application complexity is high, regardless of the complexity of the problem being solved—even simple applications are unduly complex. With Spring, the complexity of your application is proportional to the complexity of the problem being solved. However, Spring recognizes that EJB does offer developers valuable services. So Spring strives to deliver these same services while simplifying the programming model. In doing so, it adopts a simple philosophy: J2EE should be easy to use. In keeping with this philosophy, Spring was designed with the following beliefs: - Good design is more important than the underlying technology.
- JavaBeans loosely coupled through interfaces is a good model.
- Code should be easy to test.
Okay. So how does Spring help you apply this philosophy to your applications?. Good design is more important than the underlying technologyAs a developer, you should always be seeking the best design for your application, regardless of the implementation you choose. Sometimes the complexity of EJB is warranted because of the requirements of the application. Often, this is not the case. Many applications require few, if any, of the services provided by EJB yet are still implemented using this technology for technology's sake. If an application does not require distribution or declarative transaction support, it is unlikely that EJB is the best technology candidate. Yet many Java developers feel compelled to use EJB for every Java enterprise application. The idea behind Spring is that you can keep your code as simple as it needs to be. If what you want are some plain-vanilla Java objects to perform some services supported by transparent transactions, you've got it. And you don't need an EJB container, and you don't have to implement special interfaces. You just have to write your code. JavaBeans loosely coupled through interfaces is a good modelIf you are relying on EJBs to provide your application services, your components do not just depend on the EJB business interface. They are also responsible for retrieving these EJB objects from a directory, which entails a Java Naming and Directory Interface (JNDI) lookup and communicating with the bean's EJBHome interface. This is not creating a decoupled application. This is tightly coupling your application to a specific implementation, namely EJB. With Spring, your beans depend on collaborators through interfaces. Since there are no implementation-specific dependencies, Spring applications are very decoupled, testable, and easier to maintain. And because the Spring container is responsible for resolving the dependencies, the active service lookup that is involved in EJB is now out of the picture and the cost of programming to interfaces is minimized. All you need to do is create classes that communicate with each other through interfaces, and Spring takes care of the rest. Code should be easy to testTesting J2EE applications can be difficult. If you are testing EJBs within a container, you have to start up a container to execute even the most trivial of test cases. Since starting and stopping a container is expensive, developers may be tempted to skip testing all of their components. Avoiding tests because of the rigidness of a framework is not a good excuse. Because you develop Spring applications with JavaBeans, testing is cheap. There is no J2EE container to be started since you will be testing a POJO. And. since Spring makes coding to interfaces easy, your objects will be loosely coupled, making testing even easier. A thorough battery of tests should be present in all of your applications; Spring will help you accomplish this. 1.2 What is Spring?Spring is an open-source framework, created by Rod Johnson and described in his book Expert One-on-One: J2EE Design and Development.1 It was created to address the complexity of enterprise application development. Spring makes it possible to use plain-vanilla JavaBeans to achieve things that were previously only possible with EJBs. However, Spring's usefulness isn't limited to server-side development. Any Java application can benefit from Spring in terms of simplicity, testability, and loose coupling. Note: To avoid ambiguity, we'll use the term "EJB" when referring to Enterprise JavaBeans. When referring to the original JavaBean, we'll call it "JavaBean," or "bean" for short. Some other terms we may throw around are "POJO" (which stands for "plain old Java object") or "POJI" (which means "plain old Java interface"). Put simply, Spring is a lightweight inversion of control and aspect-oriented container framework. Okay, that's not so simple a description. But it does summarize what Spring does. To make more sense of Spring, let's break this description down: - Lightweight—Spring is lightweight in terms of both size and overhead. The entire Spring framework can be distributed in a single JAR file that weighs in at just over 1 MB. And the processing overhead required by Spring is negligible. What's more, Spring is nonintrusive: objects in a Spring-enabled application typically have no dependencies on Spring-specific classes.
- Inversion of control—Spring promotes loose coupling through a technique known as inversion of control (IoC). When IoC is applied, objects are passively given their dependencies instead of creating or looking for dependent objects for themselves. You can think of IoC as JNDI in reverse—instead of an object looking up dependencies from a container, the container gives the dependencies to the object at instantiation without waiting to be asked.
- Aspect-oriented—Spring comes with rich support for aspect-oriented programming that enables cohesive development by separating application business logic from system services (such as auditing and transaction management). Application objects do what they're supposed to do—perform business logic—and nothing more. They are not responsible for (or even aware of) other system concerns, such as logging or transactional support.
- Container—Spring is a container in the sense that it contains and manages the life cycle and configuration of application objects. You can configure how your each of your beans should be created—either create one single instance of your bean or produce a new instance every time one is needed based on a configurable prototype—and how they should be associated with each other. Spring should not, however, be confused with traditionally heavyweight EJB containers, which are often large and cumbersome to work with.
- Framework—Spring makes it possible to configure and compose complex applications from simpler components. In Spring, application objects are composed declaratively, typically in an XML file. Spring also provides much infrastructure functionality (transaction management, persistence framework integration, etc.), leaving the development of application logic to you.
All of these attributes of Spring enable you to write code that is cleaner, more manageable, and easier to test. They also set the stage for a variety of subframeworks within the greater Spring framework. 1.2.1 Spring modulesThe Spring framework is made up of seven well-defined modules (figure 1.1). When taken as a whole, these modules give you everything you need to develop enterprise-ready applications. But you do not have to base your application fully on the Spring framework. You are free to pick and choose the modules that suit your application and ignore the rest. As you can see, all of Spring's modules are built on top of the core container. The container defines how beans are created, configured, and managed—more of the nuts-and-bolts of Spring. You will implicitly use these classes when you configure your application. But as a developer, you will most likely be interested in the other modules that leverage the services provided by the container. These modules will provide the frameworks with which you will build your application's services, such as AOP and persistence. Figure 1.1 The Spring framework is composed of several well-defined modules. The core containerSpring's core container provides the fundamental functionality of the Spring framework. In this module you'll find Spring's BeanFactory, the heart of any Spring-based application. A BeanFactory is an implementation of the factory pattern that applies IoC to separate your application's configuration and dependency specifications from the actual application code. We discuss the core module (the center of any Spring application) throughout our book, Spring in Action from Manning Publications, starting in chapter 2, when we cover bean wiring using IoC.
摘要: 转自小小冰 http://blog.csdn.net/kellerdu/archive/2004/11/08/172247.aspx-----------------------------------------------------------------------
-------
-------
-------
--
示例:在... 阅读全文
原文地址:
http://opensource.atlassian.com/confluence/spring/display/DISC/Caching+the+result+of+methods+using+Spring+and+EHCache
导言
从
Spring 1.1.1
开始,
EHCache
就作为一种通用缓存解决方案集成进
Spring
。
我将示范拦截器的例子,它能把方法返回的结果缓存起来。
利用
Spring IoC
配置
EHCache
在
Spring
里配置
EHCache
很简单。你只需一个
ehcache.xml
文件,该文件用于配置
EHCache
:
<ehcache>
<!—设置缓存文件 .data 的创建路径。
如果该路径是 Java 系统参数,当前虚拟机会重新赋值。
下面的参数这样解释: user.home – 用户主目录 user.dir – 用户当前工作目录 java.io.tmpdir – 默认临时文件路径 --> <diskStore path="java.io.tmpdir"/>
<!—缺省缓存配置。CacheManager 会把这些配置应用到程序中。
下列属性是 defaultCache 必须的:
maxInMemory - 设定内存中创建对象的最大值。 eternal - 设置元素(译注:内存中对象)是否永久驻留。如果是,将忽略超 时限制且元素永不消亡。 timeToIdleSeconds - 设置某个元素消亡前的停顿时间。 也就是在一个元素消亡之前,两次访问时间的最大时间间隔值。 这只能在元素不是永久驻留时有效(译注:如果对象永恒不灭,则 设置该属性也无用)。 如果该值是 0 就意味着元素可以停顿无穷长的时间。 timeToLiveSeconds - 为元素设置消亡前的生存时间。 也就是一个元素从构建到消亡的最大时间间隔值。 这只能在元素不是永久驻留时有效。 overflowToDisk - 设置当内存中缓存达到 maxInMemory 限制时元素是否可写到磁盘 上。 -->
<cache name="org.taha.cache.METHOD_CACHE" maxElementsInMemory="300" eternal="false" timeToIdleSeconds="500" timeToLiveSeconds="500" overflowToDisk="true" /> </ehcache>
|
拦截器将使用
”org.taha.cache.METHOD_CACHE”
区域缓存方法返回结果。下面利用
Spring IoC
让
bean
来访问这一区域。
<!-- ====================== 缓存 ======================= -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation"> <value>classpath:ehcache.xml</value> </property> </bean>
<bean id="methodCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> <property name="cacheManager"> <ref local="cacheManager"/> </property> <property name="cacheName"> <value>org.taha.cache.METHOD_CACHE</value> </property> </bean>
|
构建我们的
MethodCacheInterceptor
该拦截器实现
org.aopalliance.intercept.MethodInterceptor
接口。一旦
运行起来
(kicks-in)
,它首先检查被拦截方法是否被配置为可缓存的。这将可选择性的配置想要缓存的
bean
方法。只要调用的方法配置为可缓存,拦截器将为该方法生成
cache key
并检查该方法返回的结果是否已缓存。如果已缓存,就返回缓存的结果,否则再次调用被拦截方法,并缓存结果供下次调用。
org.taha.interceptor.MethodCacheInterceptor
/* * Copyright 2002-2004 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *
http://www.apache.org/licenses/LICENSE-2.0
* * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
package org.taha.interceptor;
import java.io.Serializable;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log;
import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert;
import net.sf.ehcache.Cache; import net.sf.ehcache.Element;
/** * @author <a href="
mailto:irbouh@gmail.com">Omar
Irbouh</a> * @since 2004.10.07 */ public class MethodCacheInterceptor implements MethodInterceptor, InitializingBean { private static final Log logger = LogFactory.getLog(MethodCacheInterceptor.class);
private Cache cache;
/** * 设置缓存名 */ public void setCache(Cache cache) { this.cache = cache; }
/** * 检查是否提供必要参数。 */ public void afterPropertiesSet() throws Exception { Assert.notNull(cache, "A cache is required. Use setCache(Cache) to provide one."); }
/** * 主方法 * 如果某方法可被缓存就缓存其结果 * 方法结果必须是可序列化的(serializable) */ public Object invoke(MethodInvocation invocation) throws Throwable { String targetName = invocation.getThis().getClass().getName(); String methodName = invocation.getMethod().getName(); Object[] arguments = invocation.getArguments(); Object result;
logger.debug("looking for method result in cache"); String cacheKey = getCacheKey(targetName, methodName, arguments); Element element = cache.get(cacheKey); if (element == null) { //call target/sub-interceptor logger.debug("calling intercepted method"); result = invocation.proceed();
//cache method result logger.debug("caching result"); element = new Element(cacheKey, (Serializable) result); cache.put(element); } return element.getValue(); }
/** * creates cache key: targetName.methodName.argument0.argument1... */ private String getCacheKey(String targetName, String methodName, Object[] arguments) { StringBuffer sb = new StringBuffer(); sb.append(targetName) .append(".").append(methodName); if ((arguments != null) && (arguments.length != 0)) { for (int i=0; i<arguments.length; i++) { sb.append(".") .append(arguments[i]); } }
return sb.toString(); } }
|
MethodCacheInterceptor
代码说明了:
-
默认条件下,所有方法返回结果都被缓存了(
methodNames
是
null
)
-
缓存区利用
IoC
形成
-
cacheKey
的生成还包括方法参数的因素(译注:参数的改变会影响
cacheKey
)
使用
MethodCacheInterceptor
下面摘录了怎样配置
MethodCacheInterceptor
:
<bean id="methodCacheInterceptor" class="org.taha.interceptor.MethodCacheInterceptor"> <property name="cache"> <ref local="methodCache" /> </property> </bean>
<bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref local="methodCacheInterceptor"/> </property> <property name="patterns"> <list> <value>.*methodOne</value> <value>.*methodTwo</value> </list> </property> </bean>
<bean id="myBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <bean class="org.taha.beans.MyBean"/> </property> <property name="interceptorNames"> <list> <value>methodCachePointCut</value> </list> </property> </bean>
|
译注
夏昕所著《
Hibernate
开发指南》,其中他这样描述
EHCache
配置文件的:
<ehcache> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" //Cache中最大允许保存的数据数量 eternal="false" //Cache中数据是否为常量 timeToIdleSeconds="120" //缓存数据钝化时间 timeToLiveSeconds="120" //缓存数据的生存时间 overflowToDisk="true" //内存不足时,是否启用磁盘缓存 /> </ehcache>
|
摘要: 一、绪言
JDK1.5对JAVA语言进行了做了几个扩展,其中一个就是泛型。
本指南旨在介绍泛型。如果你熟悉其它语言的构造类似的东西,特别是C++的模
板(template),你会很快发现它们之间的相同点及重要的不同点;如果你在其他
地方没看到过类似的东西,那反而更好,那样你就可以开始全新的学习,用不着去忘
掉那些(对JAVA泛型)容易产生误解的东西。
泛型允许你对类型进行抽象。最常见的例子是容器类型,比如那些在Collection
层次下的类型。
阅读全文
|
|
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
27 | 28 | 29 | 30 | 31 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|
公告
常用链接
留言簿(2)
随笔分类(38)
随笔档案(43)
收藏夹(2)
Ajax
C#
博客们
最新随笔
搜索
积分与排名
最新评论
阅读排行榜
评论排行榜
|
|