【问题标题】:Inject Spring-mananged bean into Hibernate's entity将 Spring 管理的 bean 注入 Hibernate 实体
【发布时间】:2017-12-11 23:41:24
【问题描述】:

这不起作用(aspect weaving) - SlugGenerator.slugger 仍然是 null。请问有人可以看看这个并帮我一把吗?

  1. 我的想法是将spring的服务编织到实体的价值生成器中。我知道我可以使用实体的加载事件来注入该依赖项。
  2. 我已经仔细检查过 Spring 是否正确实例化了 Slugify 组件(我可以成功地将其注入控制器)。

Category.java(实体-域对象):

@Entity(name = "Category")
@Table(name = "category")
@Data
public class Category
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @GeneratorType(type = SlugGenerator.class, when = GenerationTime.ALWAYS)
    private String slug;

    // ...
}

SlugGenerator.java(值生成器 - 由 Hibernate 实例化):

@NoArgsConstructor
@Configurable(autowire = Autowire.BY_TYPE)
public class SlugGenerator implements ValueGenerator<String>
{
    @Autowired
    private Slugify slugger;

    @Override
    public String generateValue(Session session, Object owner) {
        Category category = (Category) owner;

        return slugger.slugify(category.getTitle());
    }
}

Slugify.java(Spring 托管服务):

@Component
public class SlugifyImpl implements Slugify {
    @Override
    public String slugify(String input)
    {
        // ...
    }
}

DispatcherConf.java (Spring conf.):

public class DispatcherConf extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] {ApplicationConf.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] {WebConf.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {"/*"};
    }
}

ApplicationConf.java (Spring conf.):

@Configuration
@EnableSpringConfigured
@Import({DataConf.class})
@ComponentScan(basePackages = {
        "pl.xxx.api.utils",
})
public class ApplicationConf
{
    @Bean
    public RepositoryRestConfigurer repositoryRestConfigurer() {
        return new RepositoryRestConfigurerAdapter() {
            @Override
            public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
                config.setBasePath("/api");
            }
        };
    }
}

WebConf.java (Spring conf.):

@Import(RepositoryRestMvcConfiguration.class)
public class WebConf {
}

build.gradle:

// ...
compile "org.springframework:spring-aspects:$springAspects"
// ...

jvm 类路径(等等):

aspectjrt-1.8.13.jar

智能:

Build,Execution,Deployment > Compiler > Annotation Processors > Enable Annotation Processing set to TRUE

【问题讨论】:

  • 你遇到了什么错误?
  • 从您的问题中看不到的是您使用的是编译时编织还是加载时编织。如果没有其中任何一个,它将无法正常工作。
  • @NándorElődFekete,我该怎么做? Spring 的 @EnableLoadTimeWeaving?
  • @BłażejKocik 用于加载时编织,请参阅我的 answer 以解决类似问题。简而言之,对于加载时编织,最好使用 aspectj weaver java 代理。 (可选)在aop.xml 中指定编织器选项-showWeaveInfo -verbose,详细信息here 用于调试目的。我不熟悉 gradle,所以我无法真正帮助您在 gradle 中设置编译时编织。在 maven 中,有一个名为 aspectj-maven-plugin 的插件
  • @NándorElődFekete,感谢您的宝贵时间和良好的回答! :)

标签: java spring hibernate aspectj spring-data-rest


【解决方案1】:

感谢@NándorElődFekete 的评论我明白了如何实现我的目标 - 将 Spring 管理的 bean 注入新操作员创建的实例中。

我就是这样做的:

请考虑以下注意事项:

  • 无法将 bean 注入到 ValueGenerator 实现中 (SlugGenerator.java ) - 为什么我不知道。这是一个 开放式问题:)

  • 不过,我已经成功地将 Slugify bean 注入到实体 (Category.java) 中。

在 Spring 的配置中,我只使用了@EnableSpringConfigured。

我选择使用加载时编织 (LTW),因此我在 Glassfish 域的配置文件中添加了以下行:

<jvm-options>-javaagent:/usr/local/lib/java/aspectjweaver-1.8.13.jar</jvm-options>

Category.java:

@Entity(name = "Category")
@Table(name = "category")
@Data
@Configurable(autowire = Autowire.BY_TYPE)
public class Category
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @GeneratorType(type = SlugGenerator.class, when = GenerationTime.ALWAYS)
    private String slug;

    @Autowired
    @Transient
    private Slugify slugGenerator;
    // ...
}

class SlugGenerator implements ValueGenerator<String>
{
    @Override
    public String generateValue(Session session, Object owner) {
        Category category = (Category) owner;
        Slugify slugGenerator = category.getSlugGenerator();

        return slugGenerator.slugify(category.getName());
    }
}

瞧,私有属性 slugGenerator 填充了 Slugify 接口的 bean :)

【讨论】:

  • 关于注入SlugGenerator:我看到你也在使用Lombok。我不确定它与 AspectJ 的工作情况如何,因为 Lombok 本身在实现其目标方面非常笨拙,因此可能值得尝试在不使用 Lombok 的情况下定义该类并查看它是否有效。我已经多次使用@Configurable 在非 spring 管理的 bean 中使用 spring 自动配置,但我从来没有遇到过问题。
  • 明天试试这个。感谢您的提示
  • Lombok 和 aspectj 不喜欢在同一支球队打球。虽然有办法调和它们。
【解决方案2】:

也许这种方法会有所帮助:

@Component
public final class MyBeanUtils {

    @Autowired private ApplicationContext ctx;

    private static MyBeanUtils instance;

    @PostConstruct
    private void registerInstance() {
        instance = this;
    }

    public static <T> T getBean(Class<T> clazz) {
        return instance.ctx.getBean(clazz);
    }

    public static ApplicationContext appCtx() {
        return instance.ctx;
    }
}

然后在非托管类中使用Spring bean,例如:

public class SlugGenerator implements ValueGenerator<String> {

    private Slugify slugger;

    public SlugGenerator() {
        slugger = MyBeansUtils.getBean(SlugifyImpl.class);
    }

    //...
}

【讨论】:

  • 将 ApplicationContext 注入 bean 是一种不好的做法,我相信
猜你喜欢
  • 2011-06-11
  • 2014-07-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-13
相关资源
最近更新 更多