Spring Java Configuration, @Autowire vs. Constructor Injection, @Transactional and CGLIB

We've used @Autowired

Spring-based configuration plus Java successfully , but now we're losing control. Everyone starts adding standalone dependencies everywhere, creating loops and weird bugs.

So, we are looking at the possibility of using the Spring constructor and autodevice installation.

Old:

class Bean {
   @Autowired Foo foo;
}

@Configuration
@Import( FooCfg.class )
class BeanCfg {
   @Bean public Bean bean() { return new Bean(); }
}

      

New:

class Bean {
   public Bean(Foo foo) {...}
}

@Configuration
class BeanCfg {
   @Autowired FooCfg fooCfg;
   @Bean public Bean bean() { return new Bean(fooCfg.foo()); }
}

      

This works really well (and it forces people to break beans instead of creating monsters with 10+ constructor arguments).

But it fails when it Bean

has a method annotated with @Transactional

, as CGLIB then tries to create a proxy, which fails as it cannot find a no-argument constructor.

What's the solution for this?

+3


source to share


1 answer


You have several possible solutions

  • Introduce the interfaces of your classes.
  • Update your Spring version to 4.0
  • Add protected

    no-arg constructor

Introduce interfaces

When introducing interfaces for your classes, you can opt out of using CgLib. Spring will be able to use JDK Dynamic Proxies that work with interfaces. It creates a proxy around an already existing bean instance, and this proxy implements all the interfaces of the class it wraps. This way, it doesn't matter if your class has a no-arg constructor or not.

Upgrading to Spring 4



Spring 4.0 added support for proxying classes with a missing no-arg constructor (see SPR-10594 ). To enable this update to Spring version and add Objenesis to your classpath, Spring 4 comes with its repackaged version of cglib, no longer needed.

It should be noted that you must have a logicless constructor if you are doing null checks or initialization logic in the constructor, which may fail when cglib instantiates. I suspect it is passing null to all constructor arguments (or the default for primitives).

Added protected

no-arg constructor

Cglib needs to be able to create an instance that is used to wrap the actual class. It is enough to have a constructor protected

in your classes for cglib to call it.

+5


source







All Articles