代理类中的空依赖关系

前言:我想代理一些类并拦截它们的方法(使用cglibBeanPostProcessor)。这些类是Spring bean(@Service),通常它们具有一些依赖性,例如repository

问题:当我为bean创建代理时,代理类的依赖项为null(它们没有注入代理类中)。

我应该如何正确注入代理类的依赖关系?


场景:我想为实现service接口的CompensateAware类创建代理,然后在调用其方法之前打印一些日志。

我的代码如下

服务等级(原始等级)

@Service
public class RequestTrackingService implements CompensateAware {

    @Autowired
    public RequestTrackingRepository repository;

    @Transactional
    public void startTracking() {
        RequestTrackingEntity requestTrackingEntity = new RequestTrackingEntity();
        requestTrackingEntity.setStatus(TransactionStatus.RECEIVED);
        requestTrackingEntity.setId(ServiceContext.getTrackingNo());
        repository.save(requestTrackingEntity);
    }

}

使用BeanPostProcessorcglib创建Proxt类

@Component
public class ServiceProxy implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean,String beanName) {
        if (bean instanceof CompensateAware) {
            return beanProxy(bean);
        } else return bean;
    }

    //Create proxy using cglib
    private Object beanProxy(Object bean) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(bean.getclass());
        enhancer.setCallback((MethodInterceptor) (o,method,objects,methodProxy) -> {
              System.out.println("SOME LOG BEFORE METHOD");
             return methodProxy.invokeSuper(o,objects);
        });
        return enhancer.create();
    }
}

调用service方法(startTracking

@Service
public class TestClass {

    @Autowired
    private RequestTrackingService service;

    public void test() {
        //I get NullPointerException because of null dependency (repository) in service 
        service.startTracking();
    }

}

简而言之

当我在我的应用中的某处调用startTracking方法(代理类的方法)时,我得到NullPointerException,因为它的依赖项(repository)未注入并且为空。

yuyong89 回答:代理类中的空依赖关系

增强器。create()

必要时生成一个新类,并使用指定的回调(如果 任何)来创建一个新的对象实例。使用的无参数构造函数 超类。

创建一个SuperClass配置的新实例。新实例不是Spring管理的bean,因此没有发生依赖项注入。还要注意,transactional方法的startTracking()行为也会因增强程序实例而消失。

要绕过NPE,您将需要以编程方式设置存储库bean。

我做了以下代码更改,以使代码正常工作

@Service
public class RequestTrackingService implements CompensateAware {

    public RequestTrackingRepository repository;

    public RequestTrackingService(RequestTrackingRepository repository) {
        this.repository = repository;
    }

    @Transactional
    public void startTracking() {
        RequestTrackingEntity requestTrackingEntity = new RequestTrackingEntity();
        requestTrackingEntity.setStatus(TransactionStatus.RECEIVED);
        requestTrackingEntity.setId(ServiceContext.getTrackingNo());
        repository.proxyRepoTestMethod();
    }


    public RequestTrackingRepository getRepository() {
        return repository;
    }
}

   //Create proxy using cglib
    private Object beanProxy(Object bean) {
        Enhancer enhancer = new Enhancer();
        // Set RequestTrackingService as the super class 
        enhancer.setSuperclass(((Advised)bean).getTargetClass());
        enhancer.setCallback((MethodInterceptor) (o,method,objects,methodProxy) -> {
              System.out.println("SOME LOG BEFORE METHOD");
             return methodProxy.invokeSuper(o,objects);
        });
        RequestTrackingService serviceBean = (RequestTrackingService)enhancer.create(new Class[] {RequestTrackingRepository.class},new Object[] {((RequestTrackingService)bean).getRepository()});
        return serviceBean;
    }

希望这会有所帮助

更新1:可能不是一个完整的答案。我无法通过此代码更改打印行"SOME LOG BEFORE METHOD"

更新2:结果表明bean.getClass()返回已经增强的(由spring创建的代理)对象的类。这样可以防止proxyMethod委托代码中的日志记录代码。

示例类被撤销:

class com.xxx.xxx.proxy.RequestTrackingService$$EnhancerBySpringCGLIB$$40bcb718

修改代码以设置实际的目标类也解决了日志记录问题。

enhancer.setSuperclass(((Advised)bean).getTargetClass());

最后一个问题是,您没有为此用例尝试使用Spring AOP的任何特定原因吗?

本文链接:https://www.f2er.com/2649845.html

大家都在问