Spring AOP on objects created by factories which are beans - java

I have a piece of Spring AOP advice which is not triggering when the auth(..) method is called:
#AfterReturning(pointcut="execution(* auth(..))",
returning="result")
public void trigger(final Boolean result) {
System.out.println("I was triggered " + result);
}
This is because the Authenticator object with the Auth method is not a Spring bean, but it is created by a factory which is a Spring bean:
<bean id="passwordUserAuthFact" class="foo.bar.PasswordAuthFactory">
...
</bean>
<bean id="server" class="foo.bar.Server">
<property name="authFactory" ref="passwordUserAuthFact"/>
...
</bean>
So when the application does:
session.authenticator = server.getAuthFactory().create();
... session.authenticator is an unproxied plain PasswordAuthFactory, and AOP isn't going to happen on it.
It seems to me that it should be possible to tell Spring about beans which are factories, so that it can wrap the factory in a proxy, such that objects returned by create() are themselves wrapped in an AOP proxy.
That is, Spring would dynamically create a wrapper around my factory like this:
public Foo create() {
Foo instance = target.create();
return wrapWithAopProxy(instance);
}
But I can't see a ready-made way to do that.
I would prefer not to make my classes Spring-aware. The factory class itself is third-party, so I would prefer a solution in which I don't change its source.
Is there a common pattern to achieve this? Or a better approach to the problem?

You main alternative, would be to go with programmatic aspect definition since you cannot play with the sources.
Implement a new authentication factory decorator that wraps your old authentication factory. The former would mainly delegate authenticator creation to the latter, then wraps the returned object with a ProxyBean and register the needed advice(s).
Sprig enables these beans to be loosely coupled and the authenticator POJO a non-managed bean. In below samples, I only aim to provide a glance view on how this can be done leaving implementation details up to your application:
Here down a fake Authenticator:
public class Authenticator
{
private String name;
public Authenticator( String name )
{
this.name = name;
}
public void authenticate( Object subject )
{
System.out.println( subject + " is being authenticated by: " + name );
}
}
Supposing that your AuthFactory interface looks like below:
public interface AuthFactory
{
Authenticator create();
}
It's legacy implementation, the one providing non managed authentication is as follows:
public class AuthenticationFactory implements AuthFactory
{
#Override
public Authenticator create()
{
return new Authenticator("mocked-authenticator");
}
}
Create a new MethodInterceptor (note that you may need aopalliance dependency) that encapsulates your advice logic:
public class AuthenticationAdvise implements MethodInterceptor
{
#Override
public Object invoke( MethodInvocation methodInvocation ) throws Throwable
{
System.out.println("Before invocation..."); // Your advice logic goes here
return methodInvocation.proceed();
}
}
Create a new authentication provider decorator, which will be a Spring managed bean:
public class AuthenticationFactoryDecorator implements AuthFactory {
private AuthFactory authenticationFactoryDelegate;
private MethodInterceptor interceptor;
public AuthenticationFactoryDecorator( final AuthFactory authenticationFactoryDelegate, final MethodInterceptor interceptor )
{
this.authenticationFactoryDelegate = authenticationFactoryDelegate;
this.interceptor = interceptor;
}
#Override
public Authenticator create()
{
// Create the needed pointcut
NameMatchMethodPointcut pc = new NameMatchMethodPointcut();
pc.addMethodName("authenticate");
// Get an authenticator from your legacy class
Authenticator auth = authenticationFactoryDelegate.create();
// Create a new Proxy wrapping your authFactory with the needed pointcut and advice
ProxyFactory proxyFactory = new ProxyFactory(auth);
proxyFactory.addAdvice(interceptor);
return (Authenticator) proxyFactory.getProxy();
}
}
Register the new AuthFactory bean as a Spring component and wire it with your advice and legacy factory beans (e.g. beans.xml):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="legacyAuthFactory" class="some.package.AuthenticationFactory"/>
<bean id="interceptor" class="some.package.AuthenticationFactoryAdvise"/>
<bean id="authFactory" class="some.package.AuthenticationFactoryDecorator">
<constructor-arg name="authenticationFactoryDelegate" ref="legacyAuthFactory"/>
<constructor-arg name="interceptor" ref="interceptor"/>
</bean>
</beans>
Now your are free to pull the authFactory bean from the Spring Application Context and use it to instantiate new authenticator objects:
public class MainAuthentication
{
public static void main( String[] args )
{
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:META-INF/beans.xml");
AuthFactory factory = applicationContext.getBean("authFactory", AuthFactory.class);
Authenticator authenticator = factory.create();
authenticator.authenticate(new MockSubject());
}
private static class MockSubject
{
#Override
public String toString() {
return "MockSubject";
}
}
}
Executing below main class, note that you are dealing with a new proxied authenticator instance which is wrapped with your advice logic, as the output shows:
Before invocation...
MockSubject is being authenticated!!!

Related

How to create a list filled with instances of a prototype bean using annotations?

From this Q/A: How to define a List bean in Spring? I know I can define a List<Foo> fooList filled with Foo bean instances but using XML configuration. Here's an example:
public interface Foo {
//methods here...
void fooMethod();
}
#Service("foo")
#Scope("prototype")
public class FooImpl implements Foo {
//fields and methods...
#Override
public void fooMethod() {
//...
}
}
#Service("fooCache")
#Scope
public class FooCacheImpl implements Foo {
//fields and methods...
#Override
public void fooMethod() {
//retrieves data from some cache
//...
}
}
#Service("fooWS")
#Scope("prototype")
public class FooWSImpl implements Foo {
//fields and methods...
#Override
public void fooMethod() {
//retrieves data from web service
//...
}
}
I can configure a client through XML:
<bean id="fooClient" class="some.package.FooClient">
<property name="fooList">
<list>
<bean ... /> <!-- This may be fooImpl -->
<bean ... /> <!-- This may be fooCacheImpl -->
<bean ... /> <!-- This may be fooWSImpl -->
<!-- I can have more beans here -->
</list>
</property>
</bean>
I want to know if this can be done with annotations only, no need to define the bean through XML. Something like this:
#Component
#Scope("prototype")
public class FooClient {
//which annotation(s) to use here to fill this list with FooImpl instances?
//I understand that if I have two implementations of Foo I may use a #Qualifier
//or use another list to note the different implementations.
private List<Foo> fooList;
public void bar() {
for (Foo foo : fooList) {
foo.fooMethod();
}
}
}
I think it would be better a solution that doesn't involve injecting the ApplicationContext nor the BeanFactory so FooClient is not tightly coupled to Spring classes. Also, for my case, I cannot use any Java EE classes like javax.inject.Provider as shown in this blog post: Spring 2.5.x+3.0.x: Create prototype instances from code.
What about using a Factory Bean?
I know you mentioned you did not want to be too coupled to spring - with a factory bean your bean containing the list is not so coupled - just your factory is.
Something like
#Component("fooList")
class ListFactory<List<Foo>> implements FactoryBean, ApplicationContextAware {
ApplicationContext context;
public List<Foo>> getObject() {
List<Foo> list = new ArrayList();
list.add(context.getBean("foo");
list.add(context.getBean("foo");
return list;
}
public void setApplicationContext(ApplicationContext context) {
this.context = context;
}
public boolean isSingleton() {
return false;
}
}
#Component
#Scope("prototype")
class FooClient {
#Inject
#Named("footList")
private List<Foo> fooList;
public void bar() {
for (Foo foo : fooList) {
foo.fooMethod();
}
}
}
Haven't tried it myself, or had the scenario where I've needed it so I'm not sure it will work.
If you're doing it in the code directly, then I think using the PostConstruct annotation would be the way to go:
#Component
#Scope("prototype")
public class FooClient {
....
#PostConstruct
public void init() throws Exception {
fooList = new ArrayList<Foo>();
fooList.add(new FooImpl());
}
I think using this approach would be more flexible, since I think you will struggle with annotations only if the FooImpl objects themselves require additional configuration.
That's a limitation (or feature) of prototype scope. The docs say this
In contrast to the other scopes, Spring does not manage the complete
lifecycle of a prototype bean: the container instantiates, configures,
and otherwise assembles a prototype object, and hands it to the
client, with no further record of that prototype instance.
So after Spring hands it off to you, it doesn't keep any reference to it and therefore cannot autowire any of them into your fooList. If you did add #Autowired
#Autowired
private List<Foo> fooList;
it would just create a new FooImpl object and autowire that as the single element in your List.
If you're trying to keep a reference of all the Foo instances created, you'll most likely have to do it yourself.
You can use method injection as this:
public class PrototypeClient {
protected abstract PrototypeBean createPrototype();
private List<PrototypeBean> createPrototypeList() {
int listSize = calculateListSize();
List<Prototype> result = new ArrayList<Prototype(listSize);
for (int i = 0; i < listSize; i++) {
result.add(createPrototype());
}
return result;
}
private int calculateListSize() {
// do your stuff here
}
// ...
}
and have an Spring config as:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="prototypeBean"
class="fully.qualified.class.name.of.Prototype"
scope="prototype" />
<bean id="prototyeClient"
class="fully.qualified.class.name.of.PrototypeClient">
<lookup-method name="createPrototype" bean="prototypeBean"/>
</bean>
</beans>

Spring: Delegate to custom proxy wrapper for interface injection

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.

Correct way to get beans from applicationContext Spring

I have a factory that creates instances:
public class myFactory {
public static getInstace() {
switch(someInt) {
case 1:
return new MySpringBean();
case 2:
return new MyOtherSpringBean();
}
}
}
I need to return a new instance of the beans that are "managed" by Spring bc they have Transactional business logic methods. I have read in many posts here that I should not use getBean method to get a singleton or a new instance from the applicationContext. But I cannot find the proper way to do it for my case. I have used #Resource and it seems to work but it doesn't support static fields.
Thanx
There are many ways to achieve this in spring, the most obvious way given the factory class that you have is to use JavaConfig. If you used the spring enabled JavaConfig annotations you could do the following to construct your beans and add them to the application context:
#Configuration
public class myFactory {
#Bean
public static getInstance() {
switch(someInt) {
case 1:
return new MySpringBean();
case 2:
return new MyOtherSpringBean();
}
}
}
One way is create a factory class and store the instances of the beans (each implementing a common interface MyBean) as values under some key in a map (beans):
public class MyBeanFactory {
private Map<Integer, MyBean> beans;
public MyBean create(Integer which) {
if (which != null)
return beans.get(which);
else
throw new IllegalArgumentException("Unknown bean");
}
public void setBeans(Map<Integer, MyBean> beans) {
this.beans = beans;
}
}
In your Spring applicationContext.xml now create bean a of the factory and set the beans:
<beans...>
<bean id="myBeanFactory" class="foo.bar.MyBeanFactory">
<property name="beans">
<map>
<entry key="1">
<bean class="foo.bar.MyBeanA" />
</entry>
<entry key="2">
<bean class="foo.bar.MyBeanB" />
</entry>
</map>
</property>
</bean>
</beans>
Finally you can inject your bean factory as usual and get instances from like e.g. this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:/applicationContext.xml" })
public class MyBeanFactoryTest {
#Autowired
private MyBeanFactory myBeanFactory;
#Test
public void test() {
Assert.assertTrue(myBeanFactory.create(1) instanceof MyBeanA);
Assert.assertTrue(myBeanFactory.create(2) instanceof MyBeanB);
}
}
You implement the org.springframework.beans.factory.FactoryBean interface for objects that are themselves factories.
The FactoryBean interface is a point of pluggability into the Spring IoC container's instantiation logic. If you have complex initialization code that is better expressed in Java as opposed to a (potentially) verbose amount of XML, you can create your own FactoryBean, write the complex initialization inside that class, and then plug your custom FactoryBean into the container.
The FactoryBean interface provides three methods:
Object getObject(): returns an instance of the object this factory creates. The instance can possibly be shared, depending on whether this factory returns singletons or prototypes.
boolean isSingleton(): returns true if this FactoryBean returns singletons, false otherwise.
Class getObjectType(): returns the object type returned by the getObject() method or null if the type is not known in advance
Take a look at Spring Docs

Spring FactoryBean and scopes working together

I'd like to use FactoryBeans and scopes together. Specifically, I'd like the object created and returned by a FactoryBean to be placed into a specified (perhaps custom) scope. The issue is that doing the following:
<bean class="x.y.z.TestFactoryBean" scope="test" />
Results in the FactoryBean itself being scoped, and has somewhat unpredictable behaviour on the object created by the factory. I understand why this is; the factory itself is a first-class spring-managed bean, and has its own lifecycle. However, I can't find a way to specify that the object returned from the factory should itself be scoped.
On the other hand, this does exactly what I want (as long as TestFactoryBean does NOT implement the FactoryBean interface):
<bean class="x.y.z.TestFactoryBean" name="testFactory">
<bean class="x.y.z.TestBean" factory-bean="testFactory"
factory-method="getObject" scope="test" />
So the real question is, how can I make Spring behave like it does for the 2nd example above, but using real FactoryBeans?
You can't easily use a custom scope on a bean returned from a FactoryBean.
From Spring's Java documentation:
FactoryBeans can support singletons and prototypes
If you want the FactoryBean's returned bean to have the prototype scope, then you must implement the isSingleton() method like this:
public class TestFactoryBean implements FactoryBean<TestBean> {
// the rest of the required methods are removed for simplicity reasons..
public boolean isSingleton() {
return false;
}
}
To support a custom scope, you have to implement the logic yourself and it will not be very intuitive, since the FactoryBean only provides the isSingleton() method. I will rather recommend using another solution than FactoryBean for beans with custom scope.
Hope this helps!
I solved the same issue using custom holder bean.
Factory bean:
#Component
#Configurable()
public class EventBusFactory implements FactoryBean<EventBus> {
#Override
public EventBus getObject() throws Exception {
return new SimpleEventBus();
}
#Override
public Class<?> getObjectType() {
return EventBus.class;
}
#Override
public boolean isSingleton() {
return false;
}
}
Bean holder:
#Configurable
#Component
#Scope("session")
public class EventBusHolder {
#Autowired
private EventBus eventBus;
public EventBus getEventBus() {
return eventBus;
}
public void setEventBus(EventBus eventBus) {
this.eventBus = eventBus;
}
}
And then I use holder instead of the required entity.
#Component
#Configurable
#Scope("session")
public class UicPlaceController extends PlaceController {
#Autowired
public UicPlaceController(EventBusHolder eventBus) {
super(eventBus.getEventBus());
}
...
}
The solution looks a little bit ugly, but still, it solves the issue.

Automatic dynamic binding in spring

I am using spring MVC and would like to expose default validator for javascript to use.
I have a bunch of controllers extending a common abstract class and bunch of validators implementing a common interface. The situation is something like this:
public abstract class AbstractController {
protected Validator validator;
}
public class FooController extends AbstractController{}
public class BarController extends AbstractController{}
public interface Validator {}
public class FooValidator implementes Validator{}
public class BarValidator implementes Validator{}
I would like to automatically set the validator field for each concrete controller respectivelly (so that FooController.validator would be instance of FooValidator).
The matching should be done by class names automatically.
You could create a BeanPostProcessor to do this and register it in the application context. The post processor could look for AbstractController instances with the proper naming convention, generate the validator name, instantiate the validator object via reflection, and set it in the controller. Something like this:
public Object postProcessAfterInitialization(final Object bean, final String name) throws BeansException {
if (bean instanceof AbstractController) {
String controllerName = bean.getClass().getSimpleName();
if(controllerName.endsWith("Controller")) {
String validatorName = controllerName.replaceFirst("Controller$", "Validator");
try {
Class<?> validatorClass = Class.forName(validatorName);
Validator validator = (Validator)validatorClass.newInstance();
((AbstractController)bean).setValidator(validator);
} catch(Exception e) {
throw new FatalBeanException("Cannot instantiate validator", e);
}
}
}
return bean;
}
Alternatively, if the validators are registered as Spring beans because they need dependency injection or whatever, you could create a BeanFactoryPostProcessor (not a BeanPostProcessor) that finds all the controller bean definitions by type or name, then looks up matching validator bean definitions by type or name, and adds the matching validator to the property list of each controller bean. I don't have sample code for that, but hopefully you get the idea.
Couldn't you use something like this in your configuration:
<bean id="abstractControllerTemplate" abstract="true">
<property name="validator" ref="myFormValidator"/>
</bean>
...
<bean id="someOtherConcreteController" class="com.myproj.controllers.SomeOtherConcreteController" parent="abstractControllerTemplate">
<!-- other properties specific to this controller -->
</bean>

Categories