Being a Spring framework user and
enthusiast for many years I came across several misunderstandings and
problems with this stack. Also there are places where abstractions
leak terribly and to effectively and safely take advantage of all the
features developers need to be aware of them. That is why I am
starting a Spring pitfalls series. In the first part we will
take a closer look at how proxying works.
Bean proxying is an essential and one
of the most important infrastructure features provided by Spring. It
is so important and low-level that for most of the time we don't even
realize that it exists. However transactions, aspect-oriented
programming, advanced scoping, @Async
support and various other domestic use-cases wouldn't be possible
without it. So what is proxying?
Here is an example: when you inject DAO
into service, Spring takes DAO instances and injects it directly.
That's it. However sometimes Spring needs to be aware of each and
every call made by service (and any other bean) to DAO. For instance
if DAO is marked transactional it needs to start a transaction before
call and commit or rolls back afterwards. Of course you can do this
manually, but this is tedious, error-prone and mixes concerns. That's
why we use declarative transactions on the first place.
So how does Spring implement this
interception mechanism? There are three methods from simplest to most
advanced ones. I won't discuss their advantages and disadvantages
yet, we will see them soon on a concrete examples.
Java dynamic proxies
Simplest solution. If DAO implements
any interface, Spring will create a Java dynamic
proxy implementing that interface(s) and inject it instead of the
real class. The real one
still exists and the proxy has reference to it, but to the outside
world – the proxy is the bean. Now every time you call methods on
your DAO, Spring can intercept them, add some AOP magic and call the
original method.
CGLIB generated classes
The downside of Java dynamic proxies is
a requirement on the bean to implement at least one interface. CGLIB
works around this limitation by dynamically subclassing the original
bean and adding interception logic directly by overriding every
possible method. Think of it as subclassing the original class and
calling super version amongst other things:








