将bean id记录到没有BeanNameAware接口的log4j logfile中

Gáb*_*ták 4 java logging spring javabeans

给定了一组由春天连接在一起的类.在环境中的多个实例中,有几个类用于不同的配置.他们当然有不同的beanid.

问题:

  • 当他们创建日志条目时,我们不确切知道哪个bean创建了日志,因为log4j只显示了类名
  • 我知道我可以使用spring InitializationBean + BeanNameAware接口方法实例化的logger,但我不想这样做,因为我不想在所有类中实现它们

解决方案可能是:

  • 对bean工厂有一些影响,将bean的id存储在带有bean引用的map中(key是ref,name是值)
  • 创建要应用于每个方法的方面,该方法将在调用之前在Log4j中设置"BeanName"MDC条目,并在调用之后将其还原为先前的值.同时,以前的beannames可以存储在堆栈中的threadlocal中.

问题:

  • 如何更改/配置bean工厂为我做这个技巧?我可以使用任何定制点来达到这个目的吗?
  • 如何避免beanid注册表中的映射中的内存泄漏?也许根本不需要注册表,如果以某种方式spring可以查找id作为参考.
  • 你有什么更好的想法,这不会导致改变一万个班级吗?

提前致谢.

更新: - 有没有人有原型豆的解决方案?

Mar*_*ren 5

我已经设法根据Spring AOP示例一起破解了一些东西.

我还没有达到Spring 3的速度,所以我使用Spring 2.5实现了这一点 - 我敢说有更优雅的方式来实现你想要的.为简单起见,我使用System.out实现了这一点,但这些可以很容易地转换为log4j调用.

最初,我在Spring的bean名称和对象的字符串表示形式(InitBean)之间创建了一个映射.此图用于内部MethodInterceptor的 -我没有尝试使MethodInterceptor的一个的InitializingBean在MethodInterceptor停止出于某种原因的工作.

通过MethodInterceptor传入的bean与应用程序上下文中的其他bean 之间执行等于不起作用.例如,在MethodInterceptor中使用类似" ctx.getBeansOfType(GoBean.class) "的东西.我认为这是因为通过MethodInvocation传入的对象是GoBean,而此时从应用程序上下文获取的对象是代理的(例如example.GoBean $$ EnhancerByCGLIB $$ bd27d40e).

这就是为什么我不得不求助于对象字符串表示的比较(这是不理想的).另外,我特别不想在对象上调用" toString "方法时激活MethodInterceptor逻辑(因为我在其他地方使用toString会导致无限循环和StackOverflow).

我希望这很有用,

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>
Run Code Online (Sandbox Code Playgroud)

GoBean.java

public class GoBean {
    public void execute(){
        System.out.println(new Date());
    }        
}    
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
    }    
}
Run Code Online (Sandbox Code Playgroud)

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;
    }        
}
Run Code Online (Sandbox Code Playgroud)

  • InitBean可以实现BeanPostProcessor接口,在这种情况下,一旦完全初始化,它将被传递给每个Bean对象的引用.这也将针对原型bean调用.通过使用WeakHashMap,您还可以处理内存问题 - 一旦bean没有从其他地方引用,下一个GC周期将从地图中删除相应的条目. (2认同)