java - 在没有 BeanNameAware 接口(interface)的情况下将 bean id 记录到 log4j 日志文件中

标签 java spring logging javabeans

给定一组由 spring 连接在一起的类。在环境中的多个实例中,有几个类以不同的配置使用。他们当然有不同的 beanid。

问题:

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

解决方案可能是:

  • 对 bean 工厂有一些影响,将 beans 的 id 存储在带有 bean 引用的映射中(键是引用,名称是值)
  • 创建一个应用于每个方法的方面,这将在调用前在 Log4j 中设置一个“BeanName”MDC 条目,并在调用后将其恢复为先前的值。同时,之前的 beanname 可以存储在堆栈中的线程本地中。

问题:

  • 如何更改/配置 bean 工厂来为我做这个技巧?我可以使用任何定制点来实现这个目标吗?
  • 如何避免 beanid 注册表中的映射内存泄漏?也许根本不需要注册表,如果 spring 可以以某种方式查找 id 作为引用。
  • 您有没有更好的主意,不会导致更改一万个类?

提前致谢。

更新: - 有人有原型(prototype) bean 的解决方案吗?

最佳答案

我已经设法根据 this Spring AOP Example 破解了一些东西.

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

最初,我在 Spring 的 bean 名称和对象的字符串表示 (InitBean) 之间创建了一个映射。此映射在 MethodInterceptor 中使用 - 我确实尝试将 MethodInterceptor 设为 InitializingBeanMethodInterceptor 停止工作一些原因。

在通过 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>

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;
    }        
}

关于java - 在没有 BeanNameAware 接口(interface)的情况下将 bean id 记录到 log4j 日志文件中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7323235/

相关文章:

java - 在java Draw中扩散颜色

java - 使用无参数构造函数添加到数组

java - 如何在使用 @RunWith(SpringJUnit4ClassRunner.class) 执行任何测试之前 Autowiring Junit 类中的属性

java - Spring Boot Rest Controller 通用 POST 类型

logging - Service Fabric 参与者和服务的关联 token

python - 更改级别记录到 IPython/Jupyter notebook

python-3.x - python unittest模块,记录失败到文件

java - Oracle SQL Developer - 通过一对多关系 JOIN 2 个查询

java - 当状态改变时阻止 JComponent 重新绘制

java - 如何使用Spring RestTemplate处理json类型请求和xml类型请求