Spring bean injection - inject properties after bean has been defined - java

I have an application made up of 2 projects - UI and data. In the Data project, I have added a spring bean to the xml application context:
<bean id="mail-notification-service" class="com.test.DefaultEmailNotificationManager">
</bean>
This manager sends out notifications on request, and the parameters use a simple enum and a parameters object (both of which use classes only in the data project) to select an IEmailGenerator and use it to send the emails.
The manager is defined something like:
public class DefaultEmailNotificationManager implements IEmailNotificationManager {
public MailResult sendEmail( EmailType type ) { .. }
public void register( IEmailGenerator generator ) { .. }
}
public interface IEmailGenerator {
public EmailType getType();
}
Trouble is, the generators are defined in the UI project, so they can do things like get hold of wicket page classes, the request cycle, and application resources. Thus I can't add them to the bean in the data projects' applicationContext so that other modules in both the data and UI projects can use them.
Is there any way in the applicationContext of the UI project to do something like:
<bean id="exclusionNotifier" class="com.test.ui.ExclusionEmailNotifier"/>
<bean id="modificationNotifier" class="com.test.ui.ModificationEmailNotifier"/>
<call-method bean-ref="mail-notification-service" method="register">
<param name="generatorImplementation", ref="exclusionNotifier"/>
</call-method>
<call-method bean-ref="mail-notification-service" method="register">
<param name="generatorImplementation", ref="modificationNotifier"/>
</call-method>
I can manually tie the beans together in the WicketApplication.init method but would prefer something more elegant. Has anyone done anything like this?
Using Spring 4.1.4
Thanks in advance.

Inject generators into mail-notification-service bean (e.g. using autowire="byType") and register them right after bean construction using init-method (see Initialization callbacks in Spring docs)
public class DefaultEmailNotificationManager implements IEmailNotificationManager {
private Collection<IEmailGenerator> generators;
public void init() {
for( IEmailGenerator g : generators ) {
register(g);
}
}
public void setGenerators( Collection<IEmailGenerator> generators ) {
this.generators = generators;
}
public MailResult sendEmail( EmailType type ) { .. }
private void register( IEmailGenerator generator ) { .. }
}
data's applicationContext:
<bean id="mail-notification-service"
class="com.test.DefaultEmailNotificationManager"
init-method="init"
autowire="byType" />
UI's applicationContext:
<bean id="exclusionNotifier" class="com.test.ui.ExclusionEmailNotifier"/>
<bean id="modificationNotifier" class="com.test.ui.ModificationEmailNotifier"/>

Related

is it needed to add init-method in Sprint configuration file if there is nothing to initialize

I am new to Java. I have below java class:-
#WebService
#SOAPBinding(style = SOAPBinding.Style.RPC, use = SOAPBinding.Use.LITERAL)
public class ABC extends AbstractWebService {
protected ClassNameForService classNameForService;
public void init() {
}
#WebMethod
#Path("/test")
#Produces("text/plain")
#GET
/**
*
* #return String
*/
public String test(
#WebParam(partName = "sessionID")
#QueryParam("sessionID") String sessionID
) throws UserNotDefinedException
{
// does something here
}
}
and below is my spring configuration file
<bean id=”org.testproject.webservices.ABC class=”org.testproject.webservices.ABC init-method=”init” parent=”org.testproject.webservices.AbstractWebService”>
<property name=classNameForService ref=”org.testproject.service.gb.ClassNameForService/>
</bean>
So do we need init-method=”init” here? Can I remove init-method=”init” from configuration as well as init method from class, Is it a standard practice?
You do NOT have to specify an init method (or destroy method for that matter). I think it's worth noting that you ask if it's standard practice, I believe the standard practice has moved away from the XML configuration to an annotation-driven approach but for the purpose of your question, it is standard practice to not include an init method when it is not needed.
The init-method is akin to adding a #PostContstruct annotated method on annotation declared beans.

Use Spring dependency injection on a custom Hibernate validator

I want to create my own Hibernate custom Validator and what I would like to do is to add custom logic based on some information gathered from a different context (a different Spring bean)
On my custom implementation, I have tried to both add a constructor and define the validator in a spring bean, or to use the Autowire annotation and none of them worked
Autowire example:
public class MyCustomValidator implements ConstraintValidator<CustomConstraint, String> {
#Autowired
private MyCustomChecker customChecker;
#Override
public void initialize(CustomConstraint constraintAnnotation) {
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (null == value) {
return true;
}
//get user authenticated properties to perform validation based on the user
AuthenticatedIdentity identity = Context.getAuthenticatedIdentity();
return customChecker.isWhitelisted(identity);
}
}
Constructor example:
public class MyCustomValidator implements ConstraintValidator<CustomConstraint, String> {
private MyCustomChecker customChecker;
public MetricDataSizeValidator(MyCustomChecker customChecker) {
this.customChecker = customChecker;
}
#Override
public void initialize(CustomConstraint constraintAnnotation) {
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (null == value) {
return true;
}
//get user authenticated properties to perform validation based on the user
AuthenticatedIdentity identity = Context.getAuthenticatedIdentity();
return customChecker.isWhitelisted(identity);
}
}
I've read around on the official Hibernate doc but that doesn't quite answer my question.
I am pretty sure this is a common issue when you want to validate based on some information based from a different context, however I didn't find around an answer for this.
My app is using Spring DI, where my bean is already initialized like this
<bean id="customChecker" class="com.mycomp.CustomChecker">
<constructor-arg>
<value>arg</value>
</constructor-arg>
</bean>
Is there any example around of how to achieve this?
Update
If I configure my Validator to be:
<bean id="validatorFactory" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean id="validator" factory-bean="validatorFactory"
factory-method="getValidator" />
Now I can see the validation is wired up correctly using spring beans. However, now I'm doubtful whether I'm using HibernateValidator (I think I'm not). Is there any way to achieve the same but configure HibernateValidator factory to use Spring beans?
I assume your MyCustomValidator is not recognized as a managed spring bean, so no autowiring will occur.
The easiest way to make your MyCustomValidator a spring bean is to add the #Component annotation at the class level.
You can use InitBinder in case of Spring MVC where your custom validator will automatically called by the RequestMappingHandlerAdapter.
Simply annotate your method in the controller with #InitBinder and inside the method provide your validator and provide the your validator class to WebDataBinder by calling webDataBinder.setValidator()

Atomically maintaining service layer transactions and database logging with Spring framework

I have a web application implemented using Spring and Hibernate. A typical controller method in the application looks like the following:
#RequestMapping(method = RequestMethod.POST)
public #ResponseBody
Foo saveFoo(#RequestBody Foo foo, HttpServletRequest request) throws Exception {
// authorize
User user = getAuthorizationService().authorizeUserFromRequest(request);
// service call
return fooService.saveFoo(foo);
}
And a typical service class looks like the following:
#Service
#Transactional
public class FooService implements IFooService {
#Autowired
private IFooDao fooDao;
#Override
public Foo saveFoo(Foo foo) {
// ...
}
}
Now, I want to create a Log object and insert it to database every time a Foo object is saved. These are my requirements:
The Log object should contain userId from the authorised User object.
The Log object should contain some properties from the HttpServletRequest object.
The save operation and log creation operation should be atomic. I.e. if a foo object is saved in the object we should have a corresponding log in the database indicating the user and other properties of the operation.
Since transaction management is handled in the service layer, creating the log and saving it in the controller violates the atomicity requirement.
I could pass the Log object to the FooService but that seems to be violation of separation of concerns principle since logging is a cross cutting concern.
I could move the transactional annotation to the controller which is not suggested in many of the places I have read.
I have also read about accomplishing the job using spring AOP and interceptors about which I have very little experience. But they were using information already present in the service class and I could not figure out how to pass the information from HttpServletRequest or authorised User to that interceptors.
I appreciate any direction or sample code to fulfill the requirements in this scenario.
There are multiple steps which are to be implemented to solve your problem:
Passing Log object non-obtrusively to service classes.
Create AOP based interceptors to start inserting Log instances to DB.
Maintaining the order to AOP interceptors (Transaction interceptor and Log interceptor) such that transaction interceptor is invoked first. This will ensure that user insert and log insert happens in a single transaction.
1. Passing Log object
You can use ThreadLocal to set the Log instance.
public class LogThreadLocal{
private static ThreadLocal<Log> t = new ThreadLocal();
public static void set(Log log){}
public static Log get(){}
public static void clear(){}
}
Controller:saveFoo(){
try{
Log l = //create log from user and http request.
LogThreadLocal.set(l);
fooService.saveFoo(foo);
} finally {
LogThreadLocal.clear();
}
}
2. Log Interceptor
See how spring AOP works (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop-api.html)
a) Create an annotation (acts as pointcut), #Log for method level. This annotation will be put on the service methods for which logging is to be done.
#Log
public Foo saveFoo(Foo foo) {}
b) Create an implementation, LogInteceptor (acts as the advice) of org.aopalliance.intercept.MethodInterceptor.
public class LogInterceptor implements MethodInterceptor, Ordered{
#Transactional
public final Object invoke(MethodInvocation invocation) throws Throwable {
Object r = invocation.proceed();
Log l = LogThreadLocal.get();
logService.save(l);
return r;
}
}
c) Wire the pointcut & advisor.
<bean id="logAdvice" class="com.LogInterceptor" />
<bean id="logAnnotation" class="org.springframework.aop.support.annotation.AnnotationMatchingPointcut">
<constructor-arg type="java.lang.Class" value="" />
<constructor-arg type="java.lang.Class" value="com.Log" />
</bean>
<bean id="logAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="logAdvice" />
<property name="pointcut" ref="logAnnotation" />
</bean>
3. Ordering of interceptors (transaction and log)
Make sure you implement org.springframework.core.Ordered interface to LogInterceptor and return Integer.MAX_VALUE from getOrder() method. In your spring configuration, make sure your transaction interceptor has lower order value.
So, first your transaction interceptor is called and creates a transaction. Then, your LogInterceptor is called. This interceptor first proceed the invocation (saving foo) and then save log (extracting from thread local).
One more example based Spring AOP but using java configuration, I hate XMLs :) Basically the idea is almost the same as mohit has but without ThreadLocals, Interceptor Orders and XML configs:)
So you will need :
#Loggable annotation to mark methods as the once which create the logs.
TransactionTemplate which we will use to programmatically control the transactions.
Simple Aspect which will put every thing in its place.
So at first lets create the annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Loggable {}
If you are missing the TransactionTemplate configuration or EnableAspectJAutoProxy just add following to your Java Config.
#EnableAspectJAutoProxy
#Configuration
public class ApplicationContext {
.....
#Bean
TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager){
TransactionTemplate template = new TransactionTemplate();
template.setTransactionManager(transactionManager);
return template;
}
}
And next we will need an Aspect which will do all the magic :)
#Component
#Aspect
public class LogAspect {
#Autowired
private HttpServletRequest request;
#Autowired
private TransactionTemplate template;
#Autowired
private LogService logService;
#Around("execution(* *(..)) && #annotation(loggable)")
public void logIt(ProceedingJoinPoint pjp, Loggable loggable) {
template.execute(s->{
try{
Foo foo = (Foo) pjp.proceed();
Log log = new Log();
log.setFoo(foo);
// check may be this is a internal call, not from web
if(request != null){
log.setSomeRequestData(request.getAttribute("name"));
}
logService.saveLog(log);
} catch (Throwable ex) {
// lets rollback everything
throw new RuntimeException();
}
return null;
});
}
}
And finally in your FooService
#Loggable
public Foo saveFoo(Foo foo) {}
Your controller remains the same.
If you use LocalSessionFactoryBean or it's subclass (for instance AnnotationSessionFactoryBean) with inside your Spring context, then the best option would be using entityInterceptor property. You have to pass instance of orh.hibernate.Interceptor interface. For instance:
// java file
public class LogInterceptor extends ScopedBeanInterceptor {
// you may use your authorization service to retrieve current user
#Autowired
private AutorizationService authorizationService
// or get the user from request
#Autowired
private HttpServletRequest request;
#Override
public boolean onSave(final Object entity, final Serializable id, final Object[] state, final String[] propertyNames, final Type[] types) {
// get data from request
// your save logic here
return true;
}
}
// in spring context
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" destroy-method="destroy">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
....
</property>
....
<property name="entityInterceptor" ref="logInterceptor"/>
</bean>
Add the following to your web.xml (or add listener in java code, depending on what you use).
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
Add request scope bean, so it'll be request aware.
<bean id="logInterceptor" class="LogInterceptor" scope="request">
<aop:scoped-proxy proxy-target-class="false" />
</bean>
You can separate log data fetch from interceptor, so there will be a different request scoped component, or also you can use filters to store data in ThreadLocal.

spring bean with dynamic constructor value

I need to create an Object which is in-complete without the constructor argument. Something like this
Class A {
private final int timeOut
public A(int timeout)
{
this.timeOut = timeout;
}
//...
}
I would like this Bean to be spring managed, so that I can use Spring AOP later.
<bean id="myBean" class="A" singleton="false">
</bean>
However my bean needs timeout to be passed as a dynamic value - is there a way to create a spring managed bean with dynamic value being injedcted in the constructor?
BeanFactory has a getBean(String name, Object... args) method which, according to the javadoc, allows you to specify constructor arguments which are used to override the bean definition's own arguments. So you could put a default value in the beans file, and then specify the "real" runtime values when required, e.g.
<bean id="myBean" class="A" scope="prototype">
<constructor-arg value="0"/> <!-- dummy value -->
</bean>
and then:
getBean("myBean", myTimeoutValue);
I haven't tried this myself, but it should work.
P.S. scope="prototype" is now preferable to singleton="false", which is deprecated syntax - it's more explicit, but does the same thing.
Two options spring (no pun intended) to mind:
1. create a timeout factory, and use that as the constructor parameter.
You can create a bean which implements FactoryBean, and it's job is to create other beans. So if you had something that generates salt's for encryption, you could have it return from getObject() a EncryptionSalt object. In your case you're wanting to generate Integers.
Here is an example: http://www.java2s.com/Code/Java/Spring/SpringFactoryBeanDemo.htm
2. create a timeout bean that wraps an int that's dynamically set, and leave that in the "prototype" state so it's created each time
Instead of going to the hassle of creating a factory, the EncryptionSalt object could just be declared as a prototype bean, so when it's injected a new object is created each time. Place the logic into the constructor or somewhere else.
It somewhat depends what value you want the timeout to actually be.
Do it explicitly:
interface Bean {
void setTimeout(int timeout);
}
class BeanImpl implements Bean {
private int timeout;
#Override
public void setTimeout(int timeout) {
this.timeout = timeout;
}
...
}
<bean id="bean" class="BeanImpl" scope="prototype">
...
<!-- Nothing about timeout here -->
...
</bean>
class Client {
private Bean bean;
public void setBean(Bean bean) {
this.bean = bean;
}
...
public void methodThatUsesBean() {
int timeout = calculateTimeout();
bean.setTimeout(timeout);
...
}
}

Logging bean id into log4j logfile without BeanNameAware interface

Given a set of classes wired together by spring. There are several classes that are used with different configuration in multiple instances in the environment. They have different beanid of course.
The problems:
When they make log entries, we dont know exactly which bean made the log, since the log4j displays the classname only
I know that I could use logger instantiated by spring InitializationBean+BeanNameAware interface methods, but I do not want to do it, since I do not want to implement them in all classes
The solution could be:
Having some effect on bean factory to store the id of the beans in a map with the bean reference (key is the ref, name is the value)
Creating an aspect to be applied on every method, that would set an "BeanName" MDC entry in Log4j before the call, and would restore it to the previous value after the call. Meanwhile the previous beannames could be stored in a threadlocal in a stack.
The questions:
How can I change/configure the bean factory to do this trick for me? Is there any customization point I could use to this aim?
How can I avoid memory leaks in the map in the beanid registry? Maybe the registry is not needed at all, if somehow spring can look up the id for a reference.
Do you have any better idea, that would not result in changing ten thousand classes?
Thanks in advance.
UPDATE:
- Does anyone have solution for the prototype beans?
I have managed to hack something together based on this Spring AOP Example.
I am not yet up to speed with Spring 3 so I have implemented this using Spring 2.5 - I dare say there are more elegant ways of achieving what you want. I have implemented this using System.out's for simplicity but these could easily be converted to log4j calls.
Initially I create a map between the Spring's bean names and the string representation of the object (InitBean). This map is used inside the MethodInterceptor - I did try making the MethodInterceptor an InitializingBean but the MethodInterceptor stopped working for some reason.
Performing an equals between the bean passed in via the MethodInterceptor and the other beans in the application context did not work. e.g. by using something like "ctx.getBeansOfType(GoBean.class)" inside the MethodInterceptor. I presume this is because the object passed in via the MethodInvocation was a GoBean whereas objects obtained from the application context at this point are proxied (e.g. something like example.GoBean$$EnhancerByCGLIB$$bd27d40e).
This is why I had to resort to a comparison of object string representations (which is not ideal). Also I specifically do not want to activate the MethodInterceptor logic when calling the "toString" method on an object (as since I'm using toString elsewhere leads to infinite loops and StackOverflow).
I hope this is useful,
applicationContext.xml
<beans>
<bean name="initBean" class="example.InitBean"/>
<bean name="methodLoggingInterceptor" class="example.MethodLoggingInterceptor">
<property name="initBean" ref="initBean"/>
</bean>
<bean name="proxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>go*</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>methodLoggingInterceptor</value>
</list>
</property>
</bean>
<bean name="goBean1" class="example.GoBean" />
<bean name="goBean2" class="example.GoBean" />
<bean name="goBean3" class="example.GoBean" />
</beans>
GoBean.java
public class GoBean {
public void execute(){
System.out.println(new Date());
}
}
SimpleTestClass.java
public static void main( String[] args ){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ArrayList<GoBean> goBeans = new ArrayList<GoBean>();
goBeans.add((GoBean) ctx.getBean("goBean1"));
goBeans.add((GoBean) ctx.getBean("goBean2"));
goBeans.add((GoBean) ctx.getBean("goBean3"));
for(GoBean g: goBeans){
g.execute();
}
}
InitBean.java
public class InitBean implements ApplicationContextAware, InitializingBean {
private ApplicationContext ctx;
private Map<String, String> beanMap = new HashMap<String,String>();
public void setApplicationContext(ApplicationContext ac) throws BeansException {
ctx = ac;
}
public void afterPropertiesSet() throws Exception {
for(String beanName: ctx.getBeanNamesForType(GoBean.class)){
beanMap.put(ctx.getBean(beanName).toString(), beanName);
}
}
public Map<String,String> getBeanMap(){
return beanMap;
}
}
MethodLoggingInterceptor.java
public class MethodLoggingInterceptor implements MethodInterceptor{
private InitBean initBean;
public Object invoke(MethodInvocation method) throws Throwable {
if (!"toString".equals(method.getMethod().getName())) {
StringBuilder sb = new StringBuilder();
Object obj = method.getThis();
if (obj instanceof GoBean) {
Map<String,String> beanMap = initBean.getBeanMap();
String objToString = obj.toString();
if (beanMap.containsKey(objToString)) {
System.out.println(beanMap.get(objToString));
sb.append("bean: ");
sb.append(beanMap.get(objToString));
sb.append(" : ");
}
}
sb.append(method.getMethod().getDeclaringClass());
sb.append('.');
sb.append(method.getMethod().getName());
System.out.println(sb.toString() + " starts");
Object result = method.proceed();
System.out.println(sb.toString() + " finished");
return result;
} else {
return method.proceed();
}
}
public void setInitBean(InitBean ib) {
this.initBean = ib;
}
}

Categories