Spring: Delegate to custom proxy wrapper for interface injection - java

In a very large legacy application I have interfaces and classes that do not implement those interfaces.
The interfaces are generated based on the class so the signatures are the same (except the interface adds another exception on top) and the names are similar (so it's easy to find the class name from the interface name).
To get an implementation of the interface we do a bunch of processing and logging calls but basically use java.lang.reflect.Proxy to delegate to the class. Simplified it looks like this:
// This will create a proxy and invoke handler that calls HelloWorld.doSomething
HelloWorldInterface i = MyProxyUtil.getInstance(HelloWorldInterface.class);
i.doSomething();
public interface HelloWorldInterface {
public void doSomething() throws Exception;
}
public class HelloWorld {
public void doSomething() {
//something
}
}
Is it possible with Spring annotation processing, to generically #Autowire all fields of type *Interface and have spring use MyProxyUtil.getInstance(*Interface.class) to inject the implementation?
Such that
#Autowire HelloWorldInterface a;
HelloWorldInterface b = MyProxyUtil.getInstance(HelloWorldInterface.class);
#Autowire AnotherInterface c;
AnotherInterface d = MyProxyUtil.getInstance(AnotherInterface.class);
a == b
c == d

Yes, you need to implement a AutowireCandidateResolver.
For example:
public class ProxyAutowiredCandidateResolver extends SimpleAutowireCandidateResolver {
#Override
public Object getSuggestedValue(DependencyDescriptor descriptor) {
String dependencyClassName = descriptor.getDependencyType().getSimpleName();
if (dependencyClassName.endsWith("Interface")) {
return MyProxyUtil.getInstance(descriptor.getDependencyType());
}
return super.getSuggestedValue(descriptor);
}
}
You could use a BeanFactoryPostProcessor to configure it in the application context:
public class AutowireCandidateResolverConfigurer implements BeanFactoryPostProcessor {
private AutowireCandidateResolver autowireCandidateResolver;
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
DefaultListableBeanFactory bf = (DefaultListableBeanFactory) beanFactory;
bf.setAutowireCandidateResolver(autowireCandidateResolver);
}
public AutowireCandidateResolver getAutowireCandidateResolver() {
return autowireCandidateResolver;
}
public void setAutowireCandidateResolver(
AutowireCandidateResolver autowireCandidateResolver) {
this.autowireCandidateResolver = autowireCandidateResolver;
}
}
<bean id="autowireCandidateResolverConfigurer" class="AutowireCandidateResolverConfigurer">
<property name="autowireCandidateResolver">
<bean class="ProxyAutowiredCandidateResolver" />
</property>
</bean>

If I'm reading this correctly, you should be able to define them in a JavaConfig #Configuration annotated class and then use them elsewhere.
From the docs (Spring):
#Configuration
public class AppConfig {
#Bean
public MyService myService() {
return new MyServiceImpl();
}
}
You could do something similar:
#Configuration
public class InterfaceConfig {
#Bean
public HelloWorldInterface helloWorldInterface() {
return MyProxyUtil.getInstance(HelloWorldInterface.class);
}
}
At that point, Spring would use that definition whenever that bean was needed.
You'd have to link in the #Configuration class somehow (classpath scanning, programmatically, etc), but that depends on how you're setting up your application context.
I think this should work. I've used JavaConfig quite a bit, but never quite like this. But it seems reasonable.

Related

How to specify which version of a concrete implementation for an abstract class to autowire in Spring?

Having the following class structure:
public abstract class A {
String someProperty = "property"
public abstract void doSomething();
}
#Service
public class Aa extends A {
#Override
public abstract void doSomething() {
System.out.println("I did");
}
}
#Service
public class Ab extends A {
#Override
public abstract void doSomething() {
System.out.println("I did something else");
}
}
I need a way to tell Spring which A concrete class to Autowire in my Foo service, based on a property in a properties file.
#Service
public class Foo {
#Autowire
private A assignMeAConcreteClass;
}
And in my properties file I have this:
should-Aa-be-used: {true, false}
Remove the #Service annotation, instead write a #Bean-annotated method in a configuration class that reads the properties, and returns the appropriate A instance.
Not a new way but in your case I think that a possible suitable way would be to use
FactoryBean in the class that wants to inject the bean conditionally.
The idea is simple : you implement FactoryBean by parameterizing it with the interface of the bean that you want to inject and override getObject() to inject the wished implementation :
public class FactoryBeanA implements FactoryBean<A> {
#Autowired
private ApplicationContext applicationContext;
#Value("${should-Aa-be-used}")
private boolean shouldBeUsed;
#Override
public A getObject() {
if (shouldBeUsed) {
return applicationContext.getBean(Aa.class));
return applicationContext.getBean(Ab.class));
}
}
But FactoryBean instances are not classic beans. You have to configure it specifically.
You could configure it in a Spring Java configuration in this way :
#Configuration
public class FactoryBeanAConfiguration{
#Bean(name = "factoryBeanA")
public FactoryBeanA factoryBeanA() {
return new FactoryBeanA();
}
#Bean
public beanA() throws Exception {
return factoryBeanA().getObject();
}
}

Inject a merged list of beans within #Configuration

First, let me introduce a few simple classes and interface to be able to describe my problem.
interface Basic { void foo(); }
interface Extended extends Basic { void bar(); }
class BasicService {
#Inject
List<Basic> basics;
void execute() {
basics.forEach(Basic::foo);
}
}
class ExtendedService {
#Inject
List<Extended> extendeds;
void execute() {
extendeds.forEach(Extended::bar);
}
}
#Configuration
class MyConfiguration {
// Assume, that Basic1 and Basic2 are implementations of Basic and
// Extended1 is an implementation of Extended
#Bean
public Basic basic1() {
return new Basic1();
}
#Bean
public Basic basic2() {
return new Basic2();
}
#Bean
public List<Extended> extendeds() {
return Arrays.asList(new Extended1("0"), new Extended1("1"), new Extended1("2"));
}
#Bean
public BasicService basicService() {
return new BasicService();
}
#Bean
public ExtendedService extendedService() {
return new ExtendedService();
}
}
I have two services that act on different level of abstraction. My problem is that I'm failing to find a way how I can inject all beans that implement the Basic interface in my BasicService. With the current implementation it only injects all Extended implementations, because I have a factory bean method that has a return type of List in its method signature.
I can not change the bean configuration in a way that all Extended beans have their own factory methods, because in my real code the number of Extended implementations is dynamically computed on runtime...
Is there a way I can configure Spring, so that it merges all beans with Basic and List<Basic> together in 1 big list that I can use in my BasicService?
I'm not sure whether there is a way to solve this implicitly, since Spring tries to find the best match, which the List bean seems to be (have you tried generics, e.g., List<? extends Basic> ?).
But you could do it programmatically, by getting the bean definitions from the ApplicationContext:
public BasicService(#Inject ApplicationContext ctx) {
Map<String, ? extends Basic> basicMap = ctx.getBeansOfType(Basic.class);
Map<String, Collection<? extends Basic>> basicCollectionMap = ctx.getBeansofType(ResolvableType.forClassWithGenerics(Collection.class, Basic.class));
// Now merge
Collection<? extends Basic> basics = basicMap.values();
basicCollectionMap.values().stream().map(l -> basics.addAll(l));
}
I just typed this here, so I hope there aren't any obvious errors.
I solved the problem by adding generic bean definitions for the Extended implementations. This can be done by adding a BeanDefinitionRegistryPostProcessor implementation to the #Configuration class as follows:
#Configuration
class MyConfiguration {
#Bean
public static ExtendedBeanFactory extendedBeanFactory() {
return new ExtendedBeanFactory();
}
}
class ExtendedBeanFactory implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
for (int i = 0; i < 3; i++) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(Extended1.class);
ConstructorArgumentValues args = new ConstructorArgumentValues();
args.addGenericArgumentValue(Integer.toString(i));
beanDefinition.setConstructorArgumentValues(args);
registry.registerBeanDefinition("extended_" + i, beanDefinition);
}
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// noop
}
}
This has the advantage, that consumer classes can simply inject a list of Basic or a list of Extended as the code from the question does.

Inject spring bean dynamically

In a java-spring web-app I would like to be able to dynamically inject beans.
For example I have an interface with 2 different implementations:
In my app I'm using some properties file to configure injections:
#Determines the interface type the app uses. Possible values: implA, implB
myinterface.type=implA
My injections actually loaded conditionally relaying on the properties values in the properties file. For example in this case myinterface.type=implA wherever I inject MyInterface the implementation that will be injected will be ImplA (I accomplished that by extending the Conditional annotation).
I would like that during runtime - once the properties are changed the following will happen (without server restart):
The right implementation will be injected. For example when setting myinterface.type=implB ImplB will be injected where-ever MyInterface is used
Spring Environment should be refreshed with the new values and re-injected as well to beans.
I thought of refreshing my context but that creates problems.
I thought maybe to use setters for injection and re-use those setters once properties are re-configured. Is there a working practice for such a requirement?
Any ideas?
UPDATE
As some suggested I can use a factory/registry that holds both implementations (ImplA and ImplB) and returns the right one by querying the relevant property.
If I do that I still have the second challenge - the environment. for example if my registry looks like this:
#Service
public class MyRegistry {
private String configurationValue;
private final MyInterface implA;
private final MyInterface implB;
#Inject
public MyRegistry(Environmant env, MyInterface implA, MyInterface ImplB) {
this.implA = implA;
this.implB = implB;
this.configurationValue = env.getProperty("myinterface.type");
}
public MyInterface getMyInterface() {
switch(configurationValue) {
case "implA":
return implA;
case "implB":
return implB;
}
}
}
Once property has changed I should re-inject my environment. any suggestions for that?
I know I can query that env inside the method instead of constructor but this is a performance reduction and also I would like to think of an ider for re-injecting environment (again, maybe using a setter injection?).
I would keep this task as simple as possible. Instead of conditionally load one implementation of the MyInterface interface at startup and then fire an event that triggers dynamic loading of another implementation of the same interface, I would tackle this problem in a different way, that is much simpler to implement and maintain.
First of all, I'd just load all possible implementations:
#Component
public class MyInterfaceImplementationsHolder {
#Autowired
private Map<String, MyInterface> implementations;
public MyInterface get(String impl) {
return this.implementations.get(impl);
}
}
This bean is just a holder for all implementations of the MyInterface interface. Nothing magic here, just common Spring autowiring behavior.
Now, wherever you need to inject a specific implementation of MyInterface, you could do it with the help of an interface:
public interface MyInterfaceReloader {
void changeImplementation(MyInterface impl);
}
Then, for every class that needs to be notified of a change of the implementation, just make it implement the MyInterfaceReloader interface. For instance:
#Component
public class SomeBean implements MyInterfaceReloader {
// Do not autowire
private MyInterface myInterface;
#Override
public void changeImplementation(MyInterface impl) {
this.myInterface = impl;
}
}
Finally, you need a bean that actually changes the implementation in every bean that has MyInterface as an attribute:
#Component
public class MyInterfaceImplementationUpdater {
#Autowired
private Map<String, MyInterfaceReloader> reloaders;
#Autowired
private MyInterfaceImplementationsHolder holder;
public void updateImplementations(String implBeanName) {
this.reloaders.forEach((k, v) ->
v.changeImplementation(this.holder.get(implBeanName)));
}
}
This simply autowires all beans that implement the MyInterfaceReloader interface and updates each one of them with the new implementation, which is retrieved from the holder and passed as an argument. Again, common Spring autowiring rules.
Whenever you want the implementation to be changed, you should just invoke the updateImplementations method with the name of the bean of the new implementation, which is the lower camel case simple name of the class, i.e. myImplA or myImplB for classes MyImplA and MyImplB.
You should also invoke this method at startup, so that an initial implementation is set on every bean that implements the MyInterfaceReloader interface.
I solved a similar issue by using org.apache.commons.configuration.PropertiesConfiguration and org.springframework.beans.factory.config.ServiceLocatorFactoryBean:
Let VehicleRepairService be an interface:
public interface VehicleRepairService {
void repair();
}
and CarRepairService and TruckRepairService two classes that implements it:
public class CarRepairService implements VehicleRepairService {
#Override
public void repair() {
System.out.println("repair a car");
}
}
public class TruckRepairService implements VehicleRepairService {
#Override
public void repair() {
System.out.println("repair a truck");
}
}
I create an interface for a service factory:
public interface VehicleRepairServiceFactory {
VehicleRepairService getRepairService(String serviceType);
}
Let use Config as configuration class:
#Configuration()
#ComponentScan(basePackages = "config.test")
public class Config {
#Bean
public PropertiesConfiguration configuration(){
try {
PropertiesConfiguration configuration = new PropertiesConfiguration("example.properties");
configuration
.setReloadingStrategy(new FileChangedReloadingStrategy());
return configuration;
} catch (ConfigurationException e) {
throw new IllegalStateException(e);
}
}
#Bean
public ServiceLocatorFactoryBean serviceLocatorFactoryBean() {
ServiceLocatorFactoryBean serviceLocatorFactoryBean = new ServiceLocatorFactoryBean();
serviceLocatorFactoryBean
.setServiceLocatorInterface(VehicleRepairServiceFactory.class);
return serviceLocatorFactoryBean;
}
#Bean
public CarRepairService carRepairService() {
return new CarRepairService();
}
#Bean
public TruckRepairService truckRepairService() {
return new TruckRepairService();
}
#Bean
public SomeService someService(){
return new SomeService();
}
}
By using FileChangedReloadingStrategy your configuration be reload when you change the property file.
service=truckRepairService
#service=carRepairService
Having the configuration and the factory in your service, let you can get the appropriate service from the factory using the current value of the property.
#Service
public class SomeService {
#Autowired
private VehicleRepairServiceFactory factory;
#Autowired
private PropertiesConfiguration configuration;
public void doSomething() {
String service = configuration.getString("service");
VehicleRepairService vehicleRepairService = factory.getRepairService(service);
vehicleRepairService.repair();
}
}
Hope it helps.
If I understand you correctly then the goal is not to replace injected object instances but to use different implementations during interface method call depends on some condition at run time.
If it is so then you can try to look at the Sring TargetSource mechanism in combination with ProxyFactoryBean. The point is that proxy objects will be injected to beans that uses your interface, and all the interface method calls will be sent to TargetSource target.
Let's call this "Polymorphic Proxy".
Have a look at example below:
ConditionalTargetSource.java
#Component
public class ConditionalTargetSource implements TargetSource {
#Autowired
private MyRegistry registry;
#Override
public Class<?> getTargetClass() {
return MyInterface.class;
}
#Override
public boolean isStatic() {
return false;
}
#Override
public Object getTarget() throws Exception {
return registry.getMyInterface();
}
#Override
public void releaseTarget(Object target) throws Exception {
//Do some staff here if you want to release something related to interface instances that was created with MyRegistry.
}
}
applicationContext.xml
<bean id="myInterfaceFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="MyInterface"/>
<property name="targetSource" ref="conditionalTargetSource"/>
</bean>
<bean name="conditionalTargetSource" class="ConditionalTargetSource"/>
SomeService.java
#Service
public class SomeService {
#Autowired
private MyInterface myInterfaceBean;
public void foo(){
//Here we have `myInterfaceBean` proxy that will do `conditionalTargetSource.getTarget().bar()`
myInterfaceBean.bar();
}
}
Also if you want to have both MyInterface implementations to be Spring beans, and the Spring context could not contains both instances at the same time then you can try to use ServiceLocatorFactoryBean with prototype target beans scope and Conditional annotation on target implementation classes. This approach can be used instead of MyRegistry.
P.S.
Probably Application Context refresh operation also can do what you want but it can cause other problems such as performance overheads.
This may be a duplicate question or at least very similar, anyway I answered this sort of question here: Spring bean partial autowire prototype constructor
Pretty much when you want a different beans for a dependency at run-time you need to use a prototype scope. Then you can use a configuration to return different implementations of the prototype bean. You will need to handle the logic on which implementation to return yourself, (they could even be returning 2 different singleton beans it doesn't matter) But say you want new beans, and the logic for returning the implementation is in a bean called SomeBeanWithLogic.isSomeBooleanExpression(), then you can make a configuration:
#Configuration
public class SpringConfiguration
{
#Bean
#Autowired
#Scope("prototype")
public MyInterface createBean(SomeBeanWithLogic someBeanWithLogic )
{
if (someBeanWithLogic .isSomeBooleanExpression())
{
return new ImplA(); // I could be a singleton bean
}
else
{
return new ImplB(); // I could also be a singleton bean
}
}
}
There should never be a need to reload the context. If for instance, you want the implementation of a bean to change at run-time, use the above. If you really need to reload your application, because this bean was used in constructors of a singleton bean or something weird, then you need to re-think your design, and if these beans are really singleton beans. You shouldn't be reloading the context to re-create singleton beans to achieve different run-time behavior, that is not needed.
Edit The first part of this answer answered the question about dynamically injecting beans. As asked, but I think the question is more of one: 'how can I change the implementation of a singleton bean at run-time'. This could be done with a proxy design pattern.
interface MyInterface
{
public String doStuff();
}
#Component
public class Bean implements MyInterface
{
boolean todo = false; // change me as needed
// autowire implementations or create instances within this class as needed
#Qualifier("implA")
#Autowired
MyInterface implA;
#Qualifier("implB")
#Autowired
MyInterface implB;
public String doStuff()
{
if (todo)
{
return implA.doStuff();
}
else
{
return implB.doStuff();
}
}
}
You can use #Resource annotation for injection as originally answered here
e.g.
#Component("implA")
public class ImplA implements MyInterface {
...
}
#Component("implB")
public class ImplB implements MyInterface {
...
}
#Component
public class DependentClass {
#Resource(name = "\${myinterface.type}")
private MyInterface impl;
}
and then set the implementation type in properties file as -
myinterface.type=implA
Be aware that - if interesting to know about - FileChangedReloadingStrategy makes your project highly dependent on the deployment conditions: the WAR/EAR should be exploded by container and your should have direct access to the file system, conditions that are not always met in all situations and environments.
You can use Spring #Conditional on a property value. Give both Beans the same name and it should work as only one Instance will be created.
Have a look here on how to use #Conditional on Services and Components:
http://blog.codeleak.pl/2015/11/how-to-register-components-using.html
public abstract class SystemService {
}
public class FooSystemService extends FileSystemService {
}
public class GoSystemService extends FileSystemService {
}
#Configuration
public class SystemServiceConf {
#Bean
#Conditional(SystemServiceCondition.class)
public SystemService systemService(#Value("${value.key}") value) {
switch (value) {
case A:
return new FooSystemService();
case B:
return new GoSystemService();
default:
throw new RuntimeException("unknown value ");
}
}
}
public class SystemServiceCondition implements Condition {
#Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return true;
}
}

How to AutoWire an object without Spring XML context file?

I have an Interface with Component annotation and some classes that implemented it as follows:
#Component
public interface A {
}
public class B implements A {
}
public class C implements A {
}
Also, I have a class with an Autowired variable like this:
public class Collector {
#Autowired
private Collection<A> objects;
public Collection<A> getObjects() {
return objects;
}
}
My context file consists of these definitions:
<context:component-scan base-package="org.iust.ce.me"></context:component-scan>
<bean id="objectCollector" class="org.iust.ce.me.Collector" autowire="byType"/>
<bean id="b" class="org.iust.ce.me.B"></bean>
<bean id="c" class="org.iust.ce.me.C"></bean>
And in the main class, I have some codes as follows:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
B b = (B) context.getBean("b");
C c = (C) context.getBean("c");
Collector objectCollector = (Collector) context.getBean("objectCollector");
for (A object : objectCollector.getObjects()) {
System.out.println(object);
}
Output:
org.iust.ce.me.B#1142196
org.iust.ce.me.C#a9255c
These codes work well, but for some reasons I’m not willing to use xml context file. Besides it, I prefer to create the objects with the new operator rather than using the getBean() method. Nevertheless, since the AutoWiring is really good idea in programming, I don’t want to lose it.
Now I have two questions!!
how can I AutoWire classes that implements the A Interface without using the xml context file?
Is it possible at all?
when I change the scope of a bean from singlton to
prototype as follows:
<bean id="b" class="org.iust.ce.me.B" scope="prototype"></bean>
and instantiate several beans of it, only the bean which was instantiated during creating context, is injected into AutoWired variable. Why?
Any help will be appreciated.
Not sure the version of Spring you are using. But currently you can use #Configuration to replace .xml. Take a look at #Configuration
Below is the code in documentation
#Configuration
public class ServiceConfig {
private #Autowired RepositoryConfig repositoryConfig;
public #Bean TransferService transferService() {
return new TransferServiceImpl(repositoryConfig.accountRepository());
}
}
#Configuration
public interface RepositoryConfig {
#Bean AccountRepository accountRepository();
}
#Configuration
public class DefaultRepositoryConfig implements RepositoryConfig {
public #Bean AccountRepository accountRepository() {
return new JdbcAccountRepository(...);
}
}
#Configuration
#Import({ServiceConfig.class, DefaultRepositoryConfig.class}) // import the concrete config!
public class SystemTestConfig {
public #Bean DataSource dataSource() { /* return DataSource */ }
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
Provided the classes to be managed have been correctly annotated, Spring can scan the application's files to get the information it needs without any xml or java configuration files at all.
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("com.something.something.etc");
context.refresh();
...context.getBean("name_of_bean");
Note AnnotationConfigApplicationContext is instantiated without any arguments. context.scan("..."); takes a string that tells Spring where to look. i.e. packagescom.something.something.etc.one
com.comething.something.etc.twowill be scanned, and classes within those packages annotated with #Component, #Autowired, etc. will be instatiated and injected where needed.
This approach doesn't seem to be as well documented.
1- You need to write another class that will do the operation. write #Component to B and C class.
public static void main(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
InitClass initClass = (InitClass) context.getBean("initClass");
}
public class InitClass{
#Autowired
public B b;
#Autowired
public C c;
}
with this you will get B and C without using xml.
2- http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch04s04.html Bean scopes are detailed mentioned here. If you want always a new object you should use prototype but creating a new one will be done in different classes. In the same class you should add a new reference.
like
public class InitClass{
#Autowired
public A a1;
#Autowired
public A a2;
}

What is the spring way to autowire factory created instances?

I have a controller which is supposed to create version dependend instances (currently not implemented).
#Controller
public class ReportController {
#Autowired
private ReportCompFactory reportCompFactory;
public ModelAndView getReport() {
I_Report report = reportCompFactory.getObject();
^^^^^<- no autowiring in this instance
}
...
}
The Factory looks like this:
#Component
public class ReportCompFactory implements FactoryBean<I_Report> {
#Override
public I_Report getObject() throws BeansException {
return new ReportComp();
}
#Override
public Class<?> getObjectType() {
return I_Report.class;
}
#Override
public boolean isSingleton() {
return false;
}
}
The created instances fields (#Autowired annotated ) are not set.
What should I do, is FactoryBean the right interface to implement?
I would prefer a solution which doesn't involve xml-configurations.
The component itself:
ReportComp implements I_Report {
#Autowired
private ReportDao reportDao;
^^^^^^^<- not set after creation
...
}
}
Spring doesn't perform autowiring if you create your objects. Here are a few options
define the bean to be of scope prototype - this will make the factory redundant (this is applicable in case you simply want instantiation in the factory)
inject the ReportDao in the factory, and set it to the ReportComp via a setter
inject ApplicationContext in the factory and do ctx.getAutowireCapableBeanFactory().autowireBean(instance)

Categories