Bean id logging in log4j logfile without BeanNameAware interface

Given the set of classes joined together by spring. There are several classes that are used with different configurations in multiple instances in the environment. Of course they have different beanid.

Problems:

  • When they write log entries, we don’t know exactly which bean made the log, since log4j only displays the class name
  • I know that I could use a logger created using the spring InitializationBean + BeanNameAware interface methods, but I do not want to do this because I do not want to implement them in all classes

The solution may be:

  • Having some effect on the bean factory to store the beans identifier on the map using the bean link (the key is ref, the name is value)
  • Creating an aspect that will be applied to each method that sets the MDC "BeanName" entry in Log4j before the call and restores it to its previous value after the call. Meanwhile, previous beannames could be stored in threadlocal on the stack.

Questions:

  • How do I change / customize a bean factory to do this trick for me? Is there a tuning method that I could use for this purpose?
  • How can I avoid memory leaks on the card in the beanid registry? Perhaps the registry is not needed at all, if somehow spring can find the identifier for the link.
  • Do you have an idea that will not change ten thousand classes?

Thanks in advance.

UPDATE: - Does anyone have a solution for beans prototype?

+4
source share
1 answer

I managed to hack something based on this Spring AOP example .

I am not up to speed with Spring 3 yet, so I implemented it with Spring 2.5 - I dare say that there are more elegant ways to achieve what you want. I implemented this with System.out for simplicity, but they could easily be converted to log4j calls.

First, I create a map between the Spring bean names and the string representation of the object ( InitBean ). This map is used inside the MethodInterceptor - I tried to make the MethodInterceptor the initialization bean, but the MethodInterceptor stopped working for some reason.

Performing equality between the bean passed through the MethodInterceptor and the other beans in the application context does not work. for example using something like " ctx.getBeansOfType (GoBean.class) " inside a MethodInterceptor. I assume this is because the object passed through MethodInvocation was GoBean, while the objects obtained from the application context at this point are proxied (for example, something like example.GoBean $$ EnhancerByCGLIB $$ bd27d40e ).

That's why I had to resort to comparing representations of string objects (which is not ideal). In addition, I specifically do not want to activate the MethodInterceptor logic when calling the " toString " method on an object (since, as I use toString elsewhere, this leads to infinite loops and StackOverflow).

Hope this is helpful

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; } } 
+5
source

All Articles