Spring dependency #PostConstruct - java

Say I have this dependency in a Spring #Configuration:
#Bean
public SomeClass someClass(SomeClass1 someClass1, SomeClass2 someClass2, ...) {
return new SomeClass(someClass1, someClass2, ...);
}
Say I want do do something in #PostConstruct that includes someClass dependency:
#PostConstruct
public void init() {
someClass.doSomething();
}
This cannot be injected:
#PostConstruct
public void init(SomeClass someClass) {
someClass.doSomething();
}
causes:
Caused by: java.lang.IllegalStateException: Lifecycle method annotation requires a no-arg method: ...
This cannot be autowired in the same config like this:
#Autowire
private SomeClass someClass;
#Bean
public SomeClass someClass(SomeClass1 someClass1, SomeClass2 someClass2, ...) {
return new SomeClass(someClass1, someClass2, ...);
}
as that leads to:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'globalBus': Requested bean is currently in creation: Is there an unresolvable circular reference?
A config can be split (so #Bean goes to the other config) and #Import-ed by this one and it works OK. Probably other solutoins exist - e.g. creating a separate initialization bean or so.
Is there a way to do this within one #Configuration?
Edit
As requested by #SotiriosDelimanolis, a sscce for the exception when using #Autowired:
public class ConfigPostConstructDependenciesPrb {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
ctx.getBean(Service.class);
ctx.close();
}
public static class Service {
private final Dependency dependency;
public Service(Dependency dependency) {
this.dependency = dependency;
}
public void work() {
System.out.println(dependency.getNum());
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Service [dependency=");
sb.append(dependency);
sb.append("]");
return sb.toString();
}
}
public static class Dependency {
private final int num;
public Dependency(int num) {
this.num = num;
}
public int getNum() {
return this.num;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("SomeClass1 [num=");
sb.append(num);
sb.append("]");
return sb.toString();
}
}
#Configuration
public static class BaseConfig {
#Autowired
private Service service;
#Bean
public Dependency dependency() {
return new Dependency(42);
}
#Bean
public Service service(Dependency dependency) {
return new Service(dependency);
}
#PostConstruct
public void init() {
service.work();
}
}
#Configuration
#Import(BaseConfig.class)
public static class Config {
#Autowired
private Service service;
}
}

(Tested in Spring 4.3.6)
Create a nested class inside your #Configuration and put there declarations of #Autowired service and #PostConstruct init():
#Configuration
public static class BaseConfig {
//...
#Bean
public Service service(Dependency dependency) {
return new Service(dependency);
}
#Configuration
public static class Setup {
#Autowired
private Service service;
#PostConstruct
public void init() {
service.work();
}
}
}
Below is your full example updated accordingly.
Notice that you don't have to add explicit reference to BaseConfig.Setup (look at the #Import annotation before Config class - it only refers to BaseConfig itself).
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import javax.annotation.PostConstruct;
public class ConfigPostConstructDependenciesPrb {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
ctx.getBean(Service.class);
ctx.close();
}
public static class Service {
private final Dependency dependency;
public Service(Dependency dependency) {
this.dependency = dependency;
}
public void work() {
System.out.println(dependency.getNum());
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Service [dependency=");
sb.append(dependency);
sb.append("]");
return sb.toString();
}
}
public static class Dependency {
private final int num;
public Dependency(int num) {
this.num = num;
}
public int getNum() {
return this.num;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("SomeClass1 [num=");
sb.append(num);
sb.append("]");
return sb.toString();
}
}
#Configuration
public static class BaseConfig {
#Bean
public Dependency dependency() {
return new Dependency(42);
}
#Bean
public Service service(Dependency dependency) {
return new Service(dependency);
}
#Configuration
public static class Setup {
#Autowired
private Service service;
#PostConstruct
public void init() {
service.work();
}
}
}
#Configuration
#Import(BaseConfig.class)
public static class Config {
#Autowired
private Service service;
}
}

Try this way:
public class ConfigPostConstructDependenciesPrb {
public static void main(String[] args) {
try {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(BaseConfig.class);
ctx.registerShutdownHook();
ctx.getBean(Service.class);
ctx.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
#Configuration
class BaseConfig {
#Autowired
private Service service;
#Bean
public Dependency dependency() {
return new Dependency(42);
}
#Bean
public Service service(Dependency dependency) {
return new Service(dependency);
}
#PostConstruct
public void init() {
this.service.work();
}
}
class Dependency {
private int num;
public Dependency() {
}
public Dependency(int num) {
this.num = num;
}
public int getNum() {
return this.num;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("SomeClass1 [num=");
sb.append(num);
sb.append("]");
return sb.toString();
}
}
class Service {
private Dependency dependency;
public Service() {
}
public Service(Dependency dependency) {
this.dependency = dependency;
}
public void work() {
System.out.println(dependency.getNum());
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Service [dependency=");
sb.append(dependency);
sb.append("]");
return sb.toString();
}
}

Related

Why triggered only one cache? (RedisCacheManager and CacheOperationInvocationContext issue)

I configure first_cache and it works fine.
But when I want add second_cache in FirstCasheResolver CacheOperationInvocationContext has only one cache while RedisCacheManager has two caches.
Also SecondCacheResolver even not triggered.
Please help me.
Here is my CacheConfiguration class
#EnableCaching
#Configuration
public class CacheConfiguration {
public static final String FIRST_CACHE_NAME = "first_cache";
public static final String SECOND_CACHE_NAME = "second_cache";
private int defaultTokenExpirationTime = 1000;
#Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(getDefaultRedisCacheConfiguration())
.withCacheConfiguration(FIRST_CACHE_NAME, getCustomRedisCacheConfiguration())
.withCacheConfiguration(SECOND_CACHE_NAME, getCustomRedisCacheConfiguration())
.build();
}
private RedisCacheConfiguration getDefaultRedisCacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues();
}
private RedisCacheConfiguration getCustomRedisCacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(defaultTokenExpirationTime));
}
#Bean("firstCacheResolver")
public CacheResolver firstCacheResolver(RedisCacheManager redisCacheManager) {
return new FirstCacheResolver(redisCacheManager);
}
#Bean("secondCacheResolver")
public CacheResolver secondCacheResolver(RedisCacheManager redisCacheManager) {
return new SecondCacheResolver(redisCacheManager);
}
}
Here is my FirstCacheResolver class
public class FirstCacheResolver extends SimpleCacheResolver {
public FirstCacheResolver(CacheManager cacheManager) {
super(cacheManager);
}
#Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
return super.resolveCaches(context).stream().toList();
}
}
here super.resolveCaches(context) returns list only one first_cache but CacheManager has first_cache and second_cache
Here is my SecondCacheResolver class
public class SecondCacheResolver extends SimpleCacheResolver {
public SecondCacheResolver(CacheManager cacheManager) {
super(cacheManager);
}
#Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
return super.resolveCaches(context).stream().toList();
}
}
this resolveCaches() method even not triggered
here is usage of both caches. They
public class FirstClass {
#Cacheable(
cacheNames = {CacheConfiguration.FIRST_CACHE_NAME},
key = "#params.get('first').get(0)",
cacheResolver = "firstCacheResolver"
)
public int getFirst(MultiValueMap<String, Object> params) {
// some logic
}
}
public class SecondClass {
#Cacheable(
cacheNames = {CacheConfiguration.SECOND_CACHE_NAME},
key = "#params.get('second').get(0)",
cacheResolver = "secondCacheResolver"
)
public int getSecond(MultiValueMap<String, Object> params) {
// some logic
}
}
cacheManager in debug
I try implement two caches with custom CacheResolvers.

EventListener for generic Events with Spring

I have two beans of the same class that I want to listen each for a bean-specific but generic event:
public class MyBeanClass <E> {
#EventListener
public void handleEvent(E event) { ... }
}
Config:
public class MyConfig {
#Bean
public MyBeanClass<AEvent> myBeanAClass() {
return new MyBeanClass<>();
}
#Bean
public MyBeanClass<BEvent> myBeanBClass() {
return new MyBeanClass<>();
}
}
So bean "myBeanAClass" shall listen for AEvent's and bean "myBeanBClass" shall listen for BEvent's.
Test:
#Test
public void testHandleAEvent() {
AEvent event = new AEvent();
publisher.publishEvent(event);
Mockito.verify(myBeanAClass, times(1)).handleEvent(Mockito.any()); // Fail
Mockito.verify(myBeanBClass, times(0)).handleEvent(Mockito.any());
}
Error:
org.mockito.exceptions.verification.TooManyActualInvocations:
mypackage.MyBeanClass#0 bean.handleEvent(
<any>
);
Wanted 1 time:
-> at mypackage.MyTest.testHandleAEvent(MyTest.java:45)
But was 5 times:
-> at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-> at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-> at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-> at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-> at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Because of Type Erasure the generic type E in handleEvent(E event) will be replaced with Object. After replacement class will look:
public class MyBeanClass {
#EventListener
public void handleEvent(Object event) { ... }
}
It means that such listener will accept any events from the application even generated by the spring framework internally. The method signature declares the event type it consumes. EventListener documentation
Solution 1. Create listener adapter foreach event
Adapters for base generic listener:
public class MyBeanClass <E> {
public void handleEvent(E event) {
event.toString();
}
}
public class MyBeanAClass {
private MyBeanClass<AEvent> myBeanClass;
public MyBeanAClass(MyBeanClass<AEvent> myBeanClass) {
this.myBeanClass = myBeanClass;
}
#EventListener
public void handleEvent(AEvent event) {
myBeanClass.handleEvent(event);
}
}
public class MyBeanBClass {
private MyBeanClass<BEvent> myBeanClass;
public MyBeanBClass(MyBeanClass<BEvent> myBeanClass) {
this.myBeanClass = myBeanClass;
}
#EventListener
public void handleEvent(BEvent event) {
myBeanClass.handleEvent(event);
}
}
Events:
public class AEvent extends ApplicationEvent {
private final String message;
public AEvent(Object source, String message) {
super(source);
this.message = message;
}
}
public class BEvent extends ApplicationEvent {
private final String message;
public BEvent(Object source, String message) {
super(source);
this.message = message;
}
}
Config:
public class MyConfig {
#Bean
public MyBeanAClass myBeanAClass() {
return new MyBeanAClass(new MyBeanClass<>());
}
#Bean
public MyBeanBClass myBeanBClass() {
return new MyBeanBClass(new MyBeanClass<>());
}
}
Test:
class ApplicationTests {
#MockBean
private MyBeanAClass myBeanAClass;
#MockBean
private MyBeanBClass myBeanBClass;
#Autowired
private ApplicationEventPublisher applicationEventPublisher;
#Test
public void testHandleAEvent() {
AEvent event = new AEvent(this, "Message");
applicationEventPublisher.publishEvent(event);
Mockito.verify(myBeanAClass, times(1)).handleEvent(Mockito.any());
Mockito.verify(myBeanBClass, times(0)).handleEvent(Mockito.any());
}
}
Solution 2. Generic Application Event
Create a generic event type. Implement org.springframework.core.ResolvableTypeProvider in generic event class, then listener will resolve it.
public class GenericSpringEvent<T> implements ResolvableTypeProvider {
private final T source;
public GenericSpringEvent(T source) {
this.source = source;
}
public T getSource() {
return source;
}
#Override
public ResolvableType getResolvableType() {
return ResolvableType.forClassWithGenerics(
getClass(),
ResolvableType.forInstance(this.source)
);
}
}
Implement generic listeners for each event
public class GenericSpringAEventListener {
#EventListener
public void handle(GenericSpringEvent<AEvent> event) {
event.toString();
}
}
public class GenericSpringBEventListener {
#EventListener
public void handle(GenericSpringEvent<BEvent> event) {
event.toString();
}
}
Config:
public class MyConfig {
#Bean
public GenericSpringAEventListener genericSpringAEventListener() {
return new GenericSpringAEventListener();
}
#Bean
public GenericSpringBEventListener genericSpringBEventListener() {
return new GenericSpringBEventListener();
}
}
Test:
class ApplicationTests {
#MockBean
private GenericSpringAEventListener aListener;
#MockBean
private GenericSpringBEventListener bListener;
#Autowired
private ApplicationEventPublisher applicationEventPublisher;
#Test
public void testHandleAEvent() {
AEvent event = new AEvent(this, "Message");
GenericSpringEvent<AEvent> genericEvent = new GenericSpringEvent<>(event);
applicationEventPublisher.publishEvent(genericEvent);
Mockito.verify(aListener, times(1)).handle(Mockito.any());
Mockito.verify(bListener, times(0)).handle(Mockito.any());
}
}

Why do I get null values after injecting bean?

When I try to inject the packagePropertiesList Bean in Operation.class, I get values from a properties file. But when I use operation.removeStudentFromList(), I get only null values. Do you see any problem here?
values while injecting beans
#SpringBootApplication
public class LearningCenterApplication {
public static void main(String[] args) {
SpringApplication.run(LearningCenterApplication.class, args);
ApplicationContext context =
new AnnotationConfigApplicationContext(Config.class, Operations.class, PackageProperties.class);
Operations operations = context.getBean(Operations.class);
operations.removeStudentFromList();
}
#Bean
List<PackageProperties> packagePropertiesList(List<PackageProperties> packageProperties) {
System.out.println(packageProperties);
return packageProperties;
}
#Bean
#ConfigurationProperties(prefix = "remove")
public PackageProperties removeMethod() {
return new PackageProperties();
}
#Bean
#ConfigurationProperties(prefix = "add")
public PackageProperties addMethod() {
return new PackageProperties();
}
}
#Component
public class Operations {
private List<PackageProperties> packagePropertiesList;
#Autowired
public Operations(List<PackageProperties> packagePropertiesList) {
this.packagePropertiesList = packagePropertiesList;
}
public void removeStudentFromList() {
System.out.println(packagePropertiesList);
}
}
public class PackageProperties {
private String packageName;
private String className;
private String methodName;
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
#Override
public String toString() {
return packageName + "." + className + "." + methodName;
}
}
application.properties
remove.packageName = org.epam.operations
remove.className = Operations
remove.methodName = removeStudentFromList()
add.packageName = org.epam.operations
add.className = Operations
add.methodName = addStudent()
[null.null.null] — output when operations.removeStudentFromList() is invoked
You are creating an additional ApplicationContext next to the one that's already created by Spring Boot (with new AnnotationConfigApplicationContext(). Remove that and use the existing context to get a bean, or rather have a look at the ApplicationRunner interface, if you want to run code automatically after the application has started.
The whole property handling will only work for the application context, that's created and managed by Spring Boot, not for the one that you created yourself.

Java - Singleton is causing null errors

I made a DAO class with factory method and the specific DAO returns singleton, a single instance of the DAO. But I been tracing it and its being created but I try to call on it and it always null.
Just to explain the storage factory
I call on DAOFactory to get RAMDAOFactory to get to RAMUserDAO
If there is better way to handle RAM, Serialization and SQL type DAOs or CRUD please let me know.
class that I'm calling the storage from.
public class Registration
{
private UserDAO userStorage;
private static Logger log = LogClass.getLog();
Registration(DAOFactoryType typeDataStorage)
{
userStorage = DAOFactory.getDAOFactory(typeDataStorage).getUserDAO();
log.trace("insdie Reg");
}
void addUser(String userName, String password, UserType... args)
throws Exception
{
List<UserType> userTypes = new ArrayList<UserType>(args.length);
for (UserType userType : args)
{
log.trace("userType " + userType);
userTypes.add(userType);
}
User newUser = new DefaultUser(userName, password, userTypes);
log.trace("newUser " + newUser);
if (userStorage != null)
{
userStorage.insert(newUser);
}
else
{
log.trace("userStorage null");
}
}
}
This is my DAOFactory
public abstract class DAOFactory
{
private static Logger log = LogClass.getLog();
public abstract TradeDAO getTradeDAO();
public abstract UserDAO getUserDAO();
public abstract LogDAO getLogDAO();
public static DAOFactory getDAOFactory(DAOFactoryType factoryType)
{
switch (factoryType)
{
case SQL:
return new SQLDAOFactory();
case RAM:
log.trace("insdie RAM");
return new RAMDAOFactory();
case SERIAL:
return new SerialDAOFactory();
default:
return null;
}
}
}
RAMDAOFactory
public class RAMDAOFactory extends DAOFactory
{
private static Logger log = LogClass.getLog();
private TradeDAO ramTradeDAO;
private UserDAO ramUserDAO;
private LogDAO ramLogDAO;
public RAMDAOFactory()
{
log.trace("insdie RAMDAOFactory");
RAMUserDAO.getRAMUserDAO();
RAMTradeDAO.getRAMTradeDAO();
RAMLogDAO.getRAMLogDAO();
}
#Override
public TradeDAO getTradeDAO()
{
return ramTradeDAO;
}
#Override
public UserDAO getUserDAO()
{
return ramUserDAO;
}
#Override
public LogDAO getLogDAO()
{
return ramLogDAO;
}
}
This is my UserDAO
public class RAMUserDAO implements UserDAO
{
/*
* Map<Integer, List<byte[]>> userHash; List<byte[]> arrayHashSalt;
*/
private static RAMUserDAO userDAO = null;
private Map<String, User> userList;
private static Logger log = LogClass.getLog();
private RAMUserDAO()
{
userList = new HashMap<String, User>();
log.trace("insdie RAMUserDAO constructor");
}
public static RAMUserDAO getRAMUserDAO()
{
log.trace("insdie getRAMUserDAO");
if(userDAO == null) {
log.trace("insdie new RAMUserDAO()");
userDAO = new RAMUserDAO();
}
/*if (userDAO == null)
{
synchronized (RAMUserDAO.class)
{
if (userDAO == null)
{
userDAO = new RAMUserDAO();
}
}
}*/
return userDAO;
}
#Override
public void insert(User user) throws Exception
{
log.trace("insdie insert");
userList.put(user.getUserName(), user);
}
}
The oversight was in RAMDAOFactory and fix was:
public class RAMDAOFactory extends DAOFactory
{
private static Logger log = LogClass.getLog();
#Override
public TradeDAO getTradeDAO()
{
return RAMTradeDAO.getRAMTradeDAO();
}
#Override
public UserDAO getUserDAO()
{
return RAMUserDAO.getRAMUserDAO();
}
#Override
public LogDAO getLogDAO()
{
return RAMLogDAO.getRAMLogDAO();
}
}
You've called the methods
public RAMDAOFactory()
{
log.trace("insdie RAMDAOFactory");
RAMUserDAO.getRAMUserDAO();
RAMTradeDAO.getRAMTradeDAO();
RAMLogDAO.getRAMLogDAO();
}
but you haven't assigned their value to anything
#Override
public UserDAO getUserDAO()
{
return ramUserDAO;
}
Either always call
RAMUserDao.getRAMUserDAO();
when you want to return the UserDAO or assign it to ramUserDAO and return that.

Solving "Robot legs" p‌r‌o‌b‌l‌e‌m with Spring IOC (DI)

Using Guice, one can do the following:
interface Leg {}
_
class LeftLeg implements Leg {
public String toString() {
return "LeftLeg";
}
}
_
class RightLeg implements Leg {
public String toString() {
return "RightLeg";
}
}
_
class Robot {
final Leg leftLeg_;
final Leg rightLeg_;
#Inject
Robot(#Named("left") Leg leftLeg, #Named("right") Leg rightLeg) {
leftLeg_ = leftLeg;
rightLeg_ = rightLeg;
}
public String toString() {
return "leftLeg_=" + leftLeg_ + ", rightLeg_=" + rightLeg_;
}
}
_
class RobotTest {
#Test
public void t1() throws Exception {
Injector inj = Guice.createInjector(new AnGuiceModule());
Robot r = inj.getInstance(Robot.class);
assertEquals(r.toString(), "leftLeg_=LeftLeg, rightLeg_=RightLeg");
}
}
_
class AnGuiceModule extends AbstractModule {
protected void configure() {
bind(Leg.class).annotatedWith(Names.named("left")).to(LeftLeg.class);
bind(Leg.class).annotatedWith(Names.named("right")).to(RightLeg.class);
}
}
How can i achieve the same thing with Spring 3.x (3.1.x or 3.2) using JSR-330 (optional) annotations and JavaConfig without using XML configuration?
interface Leg {}
_
#Component
class LeftLeg implements Leg {
public String toString() {
return "LeftLeg";
}
}
_
#Component
class RightLeg implements Leg {
public String toString() {
return "RightLeg";
}
}
_
class Robot {
#Autowired
Leg leftLeg_;
#Autowired
Leg rightLeg_;
public String toString() {
return "leftLeg_=" + leftLeg_ + ", rightLeg_=" + rightLeg_;
}
}
_
#RunWith(SpringJUnit4ClassRunner.class)
class RobotTest {
#Autowired
Robot r;
#Test
public void t1() throws Exception {
System.out.println(r);
}
}
You can do it like this; although this one uses Spring annotations, #Qualifier and #Autowired, though I don't see any reason for it not to work with #Named and #Inject as well, you should try:
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
#Autowired
public void prepare(#Qualifier("main") MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
Example taken from the reference.
The closest i could find is following (The definition of the Robot and Leg* classes does not change):
public class RobotTest {
#Test
public void t1() throws Exception {
ApplicationContext ctx = new
AnnotationConfigApplicationContext(RobotConfig.class, Robot.class);
Robot r = ctx.getBean(Robot.class);
assertEquals("leftLeg_=LeftLeg, rightLeg_=RightLeg", r.toString());
}
}
#Configuration
class RobotConfig {
#Bean
public Leg leftLeg() {
return new LeftLeg();
}
#Bean
public Leg rightLeg() {
return new RightLeg();
}
}
Alternative would be:
public class RobotTest {
#Test public void t1() throws Exception {
ApplicationContext ctx = new
AnnotationConfigApplicationContext(RobotConfig.class);
Robot r = ctx.getBean(Robot.class);
assertEquals("leftLeg_=LeftLeg, rightLeg_=RightLeg", r.toString());
}
}
#Configuration
class RobotConfig {
#Bean #Scope("prototype") public Robot robot() {
return new Robot(leftLeg(), rightLeg());
}
#Bean #Scope("prototype") public Leg leftLeg() {
return new LeftLeg();
}
#Bean #Scope("prototype") public Leg rightLeg() {
return new RightLeg();
}
}
There is an interesting approach described on spring forum.
You need to obtain a reference to the child context somehow, I don't like the approach presented there, but I there should be other ways.
Usage:
<bean name="someBean" class="playground.spring.BeanImportFactoryBean">
<property name="applicationContext" ref="privateCtx"/>
<property name="importBeanName" value="importBean"/>
</bean>
FactoryBean code:
public class BeanImportFactoryBean implements FactoryBean, BeanNameAware {
transient private final Log log = LogFactory.getLog(this.getClass());
private String beanName;
private ApplicationContext applicationContext;
private String importBeanName;
public BeanImportFactoryBean() {
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void setImportBeanName(String importBeanName) {
this.importBeanName = importBeanName;
}
protected String getUsedBeanName() {
String returnName;
if (importBeanName == null) {
returnName = beanName;
} else {
returnName = importBeanName;
}
return returnName;
}
public Object getObject() throws Exception {
return this.applicationContext.getBean(getUsedBeanName());
}
public Class getObjectType() {
return this.applicationContext.getType(getUsedBeanName());
}
public boolean isSingleton() {
return this.applicationContext.isSingleton(getUsedBeanName());
}
}

Categories

Resources