Sunday, March 28, 2010

Annotation-Based Transactions

Spring provides several different approaches to transaction management:
  • Programmatic: You can write your transactions using Java source code directly. Normally you wouldn't do this unless you needed fine-grained control over some particular transaction.
  • Declarative: You can declare transaction definitions in either a centralized way using XML or in a distributed way using annotations:
    • XML-based: You can configure transactions in Spring's centralized application context file. Once again you have options:
      • Proxy-based: In this approach you wrap your service beans with transactional proxies. The proxy and the service bean both implement the same Java interface so the application can't tell them apart. This is a fairly verbose approach with respect to the actual context configuration though there are techniques you can use to streamline the configuration.
      • AOP-based: Here you define AOP aspects to endow your service beans with transactional semantics. Not quite as verbose as the proxy-based approach.
    • Annotation-based: You can use Java 5 annotations to distribute transaction configuration across Java classes.
With Spring, you typically apply transaction annotations either to Java interfaces for service beans, or else to the service beans themselves. If you apply the annotations to the interfaces then the transaction definition holds true for any classes implementing those interfaces. We'll do that here, but remember that you can apply the annotations to the service beans themselves as well.
Here's an interface for a simple article service. This service allows the application to get an article by ID, and also to post a comment for a given article.
The first thing to notice is again just how ridiculously simple this is. I probably don't need to explain it but I will anyway just to be safe. The @Transactional annotation we define on the interface is setting default values for the various methods that form the interface. So we are saying here that unless the method itself specifies otherwise, we want Propagation.REQUIRED for the propagation behavior, we want the default isolation level, and we want to flag methods as read-only.
The only other piece to mention is that I've overridden the readOnly setting for the postComment method since that's obviously a write method.
If it could be any simpler I'm not sure how. Now let's look at the Spring configuration file.

That's it—really! Make sure you include both the aop and tx namespaces and schema locations since that's where the magic lives. You have to wire your beans up just like you normally would. And you have to provide a transaction manager of one kind or another. I'm using the Hibernate 3 HibernateTransactionManager but use whatever you want. If you give your transaction manager the id transactionManager, then you can take advantage of a little Spring convention-over-configuration: <tx:annotation-driven> will pick that up automatically. (And if you want to call your transaction manager something else, that's fine too. Just reference that ID using the transaction-manager attribute of the <tx:annotation-driven> element.)
Oh, the <tx:annotation-driven> element just tells Spring that you want it to pick the transaction definitions up from the Java annotations. I'm not sure how it works behind the scenes, but I think Spring will run through the beans in your context and create the necessary transaction aspects. Not positive about that—if you know the details, I'm interested—but in any case you end up with annotation-driven transactions. Nice!

Friday, March 26, 2010

Transaction Basics

The core idea behind a transaction is that it's a complex operation completed as an all-or-nothing set of simpler operations. If one of the simpler operations fails, then none of the operations should be applied.
The classic example is making a purchase, and indeed this is probably where the name "transaction" comes from. There are several steps:
  1. Pull funds from buyer's account
  2. Add funds to seller's account
  3. Decrease product inventory
A failure could happen at any of those steps. For example, at step 1, if the buyer doesn't have enough money, then the transaction should fail. (We wouldn't add funds to the seller's account and we wouldn't decrease product inventory.) At step 2, if the seller's account has been frozen due to suspected involvement in illegal activities, then the transaction should fail. At step 3, if the product is out of stock, then again the transaction should fail.

ACID Properties

ACID is an acronym that stands for atomic, consistent, isolated and durable. An operation is a transaction if and only if it has these four characteristics:
  • Atomic: This is the aforementioned all-or-nothing property. Even though a transaction comprises multiple operations, it is completed as a single logical unit of work. Either the whole thing succeeds or none of it does.
  • Consistent: We want our "transactional resource" (which in most cases means our database) to be consistent with reality. So for example if I have 4,132 widgets in stock after I sell you five of them, then I want the database to say that I have 4,132 widgets in stock after I run a sell(you, 5, widget) transaction. The consistency property means that after a transaction completes, the database (or whatever transactional resource we're using) matches up with the real world.
  • Isolated: In general we want to be able to run lots of transactions against the database at the same time, and we don't want to make a big mess out of things in the process. The isolation property means that when you run a transaction, it achieves its results without interference from other transactions. That doesn't mean that the transactions can't run concurrently—it just means that the transactions shouldn't corrupt each other in the process. In practice it's nontrivial to strike the right balance between concurrency and isolation; transactions however exhibit some level of isolation, and well-designed transactions exhibit the "right" amount of isolation.
  • Durable: This just means that after a transaction has ended, its results are made persistent. Probably they would have called this property "persistent" instead of "durable", but "ACIP" is not as cool as "ACID".

Defining Individual Transactions

Now that we know what transactions are, we need to understand how individual transactions are actually specified. Defining a transaction involves picking a chunk of code (maybe a method, maybe a set of methods, maybe a block of code inside a method) and setting values for the following five parameters:
  • Propagation behavior: When defining a transaction we must specify its "boundaries": where does the transaction start and where does it end? In Spring (and also in EJB), the boundaries of a transaction may or may not coincide with the boundaries of a Java method. In one respect this is not unlike using the synchronized keyword: if one synchronized method calls another on the same class, then the protected scope includes both methods, not just one, and so the boundaries do not coincide with a single method. But the difference is that with transactions you have a lot more flexibility as far as defining the boundaries. Certainly it is possible to enter a transaction starting from one method and then include additional method calls within the scope of that initial transaction. But you can do other things too, such as declare that calls to other methods open up new transactions, or that a given method must always run within the scope of an existing transaction, etc. I won't go over all the options here but there are seven and you can see them here: transaction propagation options. Probably PROPAGATION_REQUIRED is the most typical.
  • Isolation level: I mentioned above that in practice concurrency trades against isolation. (Once again there's an analogy with threads, incidentally.) You can specify the level of isolation you need for a given transaction; the general rule of thumb is assign the weakest isolation level you can safely get away with so as to maximize concurrency. Again I won't go into the details but you can find them here: transaction isolation levels. The most typical cases are ISOLATION_READ_COMMITTED and ISOLATION_REPEATABLE_READ. The ISOLATION_READ_UNCOMMITTED is so weak as to be almost useless in practice, and ISOLATION_SERIALIZABLE is so strong that you don't want to use it unless you really, really need the safety it provides: it's a concurrency-killer.
  • Timeout: Transaction timeouts allow the calling application to give up if the database hasn't completed the transaction within a specifiable interval of time.
  • Read-only: This flag indicates whether the transaction will be, well, read-only. If so, you can flag it as such and the underlying database or other resource can apply optimizations based on that fact.
  • Rollback behavior: By default, both Spring and EJB roll back a transaction (i.e., cancel it without applying any of the changes) when runtime exceptions, but not when checked exceptions occur. You can modify that behavior.

Friday, March 12, 2010

Annotation-Based Autowiring in Spring 2.5

Add annotations to name your DAO, service and controller classes
Chances are good that your DAO and service classes don't have the names that name-based autowiring would require. For example, you might define interfaces that have the "right" names, such as a CategoryDao interface, or a ProductService interface, and then your concrete implementation classes would be HibernateCategoryDao or ProductServiceImpl (or whatever), which won't autowire to the desired properties unless you have some strange and ill-advised property names. So our first order of business is to provide the requisite names. With manual wiring, you provide this on the <bean> element using the id or name attributes. But we're trying to eliminate said elements from our config, so that option is unavailable. We use annotations instead.

For each DAO, add a class-level @Repository annotation. These annotations go on the implementation class, not on the interface.
The @Repository annotation works in Spring 2.0 as well.

For each service component, add a class-level @Service annotation. As before, these go on the implementation class, not on the interface.

Note that @Service is new with Spring 2.5. So it won't work if you're using Spring 2.0 or earlier.

For each Spring MVC controller, add a class-level @Controller annotation.
Don't worry about providing a name; we won't need it. (So this step is a little out of place in these instructions, but go ahead and do it anyway as you will need the @Controller annotation if you want to fully autowire the web tier.) Just do this for each controller:

Like the @Service annotation, @Controller is new with Spring 2.5.
At this point we've haven't really changed anything; you still have names defined in the manual configurations in addition to the annotation-based names you've just added. Test out your app to make sure we haven't broken anything, and then move on to the next step.

We have to tell Spring two things: where to find the names, and what strategy to use (viz., autowiring by name) for autowiring.

Tell Spring where to find the annotation-based names
You will need to use the <context:component-scan> element to do this. Since it's in the context namespace, you must declare that namespace and schema location in your Spring config files. Here are examples from the data access, service, and web configurations:
In the above, the pieces relevant to component names are the xmlns:context declaration, the xsi:schemaLocation declaration, and the <context:component-scan> configuration. I'm telling Spring to scan the x.y.dao package for components that have the @Repository annotation, to scan the x.y.service package for components that have the @Service annotation, and to scan x.y.web for components that have the @Controller annotation. Spring will do that, and in the case of the data access and service components, it will use the value we provided to the annotations in step 1 above as a basis for name-based autowiring. (We didn't provide any names with the @Controller annotation though I would assume you can do that. It happens that in our case we won't need it.)
You'll notice however that I've snuck in some default-autowire="byName" attributes in there. As you can guess, that's for autowiring, and we'll look at that in just a second.

Make sure you have public setters for each bean that you want autowired
It appears that default-autowire="byName" autowiring is based on public setters. (With the @Autowired attribute applied to fields you can avoid the setters, but if you have unit tests, you'll need setters to inject mocks, and so you may as well just keep the setters and make them public. Weaker visibility doesn't appear to work)

Tell Spring that you want to use name-based autowiring
The default-autowire="byName" attribute tells Spring that you want to use component names to automatically wire up the app. In step 1 above we went through the process of providing correct names ("correct" here means names that match the injection property names) for DAO and service classes. That will allow us to remove the DAO and service components from our Spring config. In all likelihood there will be other components that you can't remove from the config, such as a Hibernate SessionFactory in your data access configuration or a TransactionManager in your services configuration. In cases like that, just make sure that the names (or IDs) that you give to the components are the ones that would be expected when doing name-based injection. Here are some examples:
Note that using default-autowire="byName" allows you to avoid having to use the @Autowired attribute on your various dependency injection fields or setters. You shouldn't have to use that at all if you follow these instructions.
At this point you should be able to remove the following configurations:
  • The DAO component definitions from your Spring data access configuration file (but don't remove the SessionFactory).
  • The service component definitions from your Spring service configuration file (but don't remove the TransactionManager).
  • The service injections from your MVC controllers in your web configuration file. Don't remove the controllers themselves for now; you still need those for defining URL mappings. Just remove the service injections since those will now be autowired. (Note that there's a way to eliminate the MVC controller configurations as well
  • The sessionFactory injection from your TransactionManager definition since that will be autowired, the dataSource injection from your SessionFactory (assuming you have an appropriate ID on the DataSource config), etc. In general just look through your configs for elements that will now be autowired and either comment them out or remove them.
I would recommend commenting things out first and then testing the app to make sure it still works.

Wednesday, March 3, 2010

Compact Attribute Declaration

Attributes in a class don't have to be declared in the verbose way:

Attributes of the same type and visibility can be declared in a more compact manner:

This works in most cases - except you want to annotate each attribute in different way....

Tuesday, March 2, 2010

Reflection is bad

My personal opinion: "Reflection is evil and should be avoided whenever it's possible"

List of reasons why reflection is bad:
  1. It is hack of compiler. Compiler is not able to check code consistency if you use reflection. Problems with incorrect names or types will popup only at runtime
  2. Automatic development tools are not able to work with reflections code. E.g. in Eclipse instead of Java search for method names, types declarations or references you have only plain text search. All automatic refactoring or code analysis tools became useless.
  3. It's difficult to debug reflections code.
  4. Reflection complicates understanding and navigation in code. For regular call of method I can get Java help popup or go to method body (just by Ctr+click). It's not possible for the method which is called by reflection. Code assistant doesn't work also. It's like writing code in the Notepad.
  5. For me all above reasons are sufficient for avoiding refactoring. But there is one more – significant performance penalty. I have created a simple test. It shows that method invocation by reflection is 60 times slower than regular! Even with some optimization (if we call the same method multiple times) it's 5 times slower.
Here is code of my performance test:
Test ouput:
direct call time = 31 msec. reflection time = 1797 msec. reflection (optimized) time = 157 msec.

Discussions on Sun Java forum
More Discussions on Sun Java forum
More Discussions on Sun Java forum
"A general rule of thumb: if your design uses reflection, then rethink your design; you can probably solve the problem better with cleaner decomposition of classes, better polymorphism, etc."

A good discussion on reflection (with actual statistics) can be found here
Here is small article of Christian Cryder


If you think this is directed to anyone in particular: If the suit fits wear it #LOL