使用@Configurable进行Spring自动装配

发布于 2024-10-11 22:24:02 字数 1750 浏览 5 评论 0原文

我正在考虑使用 Spring @Configurable 和 @Autowire 将 DAO 注入域对象,这样它们就不需要持久层的直接知识。

我正在尝试遵循 http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurable,但我的代码似乎没有效果。

基本上,我有:

@Configurable
public class Artist {

    @Autowired
    private ArtistDAO artistDao;

    public void setArtistDao(ArtistDAO artistDao) {
        this.artistDao = artistDao;
    }

    public void save() {
        artistDao.save(this);
    }

}

public interface ArtistDAO {

    public void save(Artist artist);

}

并且

@Component
public class ArtistDAOImpl implements ArtistDAO {

    @Override
    public void save(Artist artist) {
        System.out.println("saving");
    }

}

在 application-context.xml 中,我有:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springsource.org/dtd/spring-beans-2.0.dtd">
<beans>

    <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
    <bean class="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect" factory-method="aspectOf"/>

</beans>

类路径扫描和初始化由 Play 的 spring 模块执行!框架,尽管其他自动装配 bean 也可以工作,所以我很确定这不是根本原因。我正在使用 Spring 3.0.5。

在其他代码中(事实上,在使用 Spring 注入控制器的 bean 方法内),我这样做:

Artist artist = new Artist();
artist.save();

这给了我一个 NullPointerException 试图访问 Artist.save() 中的artistDao。

知道我做错了什么吗?

马丁

I'm playing with the idea of using Spring @Configurable and @Autowire to inject DAOs into domain objects so that they do not need direct knowledge of the persistence layer.

I'm trying to follow http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurable, but my code seems to have no effect.

Basically, I have:

@Configurable
public class Artist {

    @Autowired
    private ArtistDAO artistDao;

    public void setArtistDao(ArtistDAO artistDao) {
        this.artistDao = artistDao;
    }

    public void save() {
        artistDao.save(this);
    }

}

And:

public interface ArtistDAO {

    public void save(Artist artist);

}

and

@Component
public class ArtistDAOImpl implements ArtistDAO {

    @Override
    public void save(Artist artist) {
        System.out.println("saving");
    }

}

In application-context.xml, I have:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springsource.org/dtd/spring-beans-2.0.dtd">
<beans>

    <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
    <bean class="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect" factory-method="aspectOf"/>

</beans>

Class path scanning and initialisation is performed by the spring module for Play! framework, although other autowired beans work, so I'm pretty sure this is not the root cause. I'm using Spring 3.0.5.

In other code (inside a method in bean that's injected into my controller using Spring, in fact), I'm doing this:

Artist artist = new Artist();
artist.save();

This gives me a NullPointerException trying to access the artistDao in Artist.save().

Any idea what I'm doing wrong?

Martin

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

辞慾 2024-10-18 22:24:02

您需要启用加载时编织(或其他类型的编织)才能使用@Configurable。确保正确启用它,如 7.8.4 在 Spring 框架中使用 AspectJ 进行加载时编织

You need to enable load-time weaving (or other kinds of weaving) in order to use @Configurable. Make sure you enabled it correctly, as described in 7.8.4 Load-time weaving with AspectJ in the Spring Framework.

骄兵必败 2024-10-18 22:24:02

我在使用 LTW 尝试将 bean 自动装配到我的域类中时遇到了 Tomcat 7 的问题。

3.2.x 的文档有一些更新,位于 http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-configurable-container 揭示了可以使用 @EnableSpringConfigured 而不是 xml 配置。

因此,我的 Domain 对象上有以下注释:

@Configurable(preConstruction=true,dependencyCheck=true,autowire=Autowire.BY_TYPE)
@EnableSpringConfigured

@EnableSpringConfigured 是一个替代品

<context:spring-configured />

,并且不要忘记将其添加到您的上下文 xml 文件中:

<context:load-time-weaver weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver" aspectj-weaving="on"/>

当然,我需要首先设置 Tomcat 进行加载时编织。

另外,我在 3.2.0 中遇到了一个错误(空指针),所以我需要升级到 Spring 3.2.1 (https://jira.springsource.org/browse/SPR-10108

现在一切都很好!

I was having this problem with Tomcat 7 using LTW trying to autowire beans into my domain classes.

There was some updates to the doc for 3.2.x at http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-configurable-container that revealed that one can use @EnableSpringConfigured instead of the xml configuration .

So I have the following annotation on my Domain object:

@Configurable(preConstruction=true,dependencyCheck=true,autowire=Autowire.BY_TYPE)
@EnableSpringConfigured

@EnableSpringConfigured is a substitue for

<context:spring-configured />

and don't forget to add this to your context xml file:

<context:load-time-weaver weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver" aspectj-weaving="on"/>

Of course I needed to setup Tomcat for load time weaving first.

Also, I ran into a bug in 3.2.0 (null pointer) so I needed to upgrade to Spring 3.2.1 (https://jira.springsource.org/browse/SPR-10108)

All is well now!

鹿童谣 2024-10-18 22:24:02

你应该看看 Spring Roo 是如何做的,因为它正是你想做的。

有很多事情可能会导致 NPE,但大多数情况下,它与未使用 AspectJ 编译器 正确编译以及没有 Spring Aspects jar 有关您的 AspectJ lib 路径(这与您的类路径不同)。

首先尝试让它与 Maven 和 AspectJ 编译器插件一起工作。这就是我推荐 Spring Roo 的原因,因为它会生成具有正确设置的 POM 文件。

我发现 @Configurable 并不能真正与 LTW 一起使用(尽管答案之一是这么说的)。您需要编译时编织才能使 @Configurable 工作,因为建议发生在对象构造时(构造函数建议不能使用 Springs LTW 完成)。

You should just look how Spring Roo does it since it does exactly what you want to do.

There are lots of things that can cause the NPE your having but most of the time it has to do with not compiling properly with AspectJ compiler and not having the Spring Aspects jar in your AspectJ lib path (this is different than your classpath).

First just try to get it to work with Maven and the AspectJ compiler plugin. Thats why I recommend Spring Roo as it will generate a POM file with the correct setup.

I have found @Configurable does not really work with LTW (despite one of the answers saying so). You need compile time weaving for @Configurable to work because the advice is happening at object construction time (constructor advice cannot be done with Springs LTW).

懷念過去 2024-10-18 22:24:02

首先,启用 Spring 调试日志记录。我使用 Log4j 来做到这一点。我创建了一个像这样的记录器(使用 Log4j xml 配置,以便我可以使用 RollingFileAppender):

<log4j:configuration>
  <appender name="roll" class="org.apache.log4j.rolling.RollingFileAppender">
     blah blah configuration blah blah
  </appender>
  <logger name="org.springframework">
    <level value="debug" />
    <appender-ref ref="roll" />
  </logger>
</log4j:configuration>

这将允许您查看 Spring 正在做什么以及何时做什么。

其次,您已经自动装配了 ArtistDAO,但我看不到您在哪里有一个名为 ArtistDAO 的 bean。默认情况下,您的 DAO 组件 bean 将被命名为“artistDaoImpl”。尝试将 @Component 更改为 @Component("artistDao") 并将 @Autowired 应用于 setter:

private ArtistDAO artistDao;

@Autowired
public void setArtistDao(ArtistDAO artistDao) 
{
  this.artistDao = artistDao;
}

First, enable Spring debug logging. I use Log4j to do it. I've created a logger like so (with Log4j xml configuration so I can use RollingFileAppender):

<log4j:configuration>
  <appender name="roll" class="org.apache.log4j.rolling.RollingFileAppender">
     blah blah configuration blah blah
  </appender>
  <logger name="org.springframework">
    <level value="debug" />
    <appender-ref ref="roll" />
  </logger>
</log4j:configuration>

This will allow you to see what Spring is doing and when.

Second, you have ArtistDAO autowired but I don't see where you have a bean named ArtistDAO. Your DAO component bean will be named "artistDaoImpl" by default. Try changing @Component to @Component("artistDao") and applying @Autowired to the setter instead:

private ArtistDAO artistDao;

@Autowired
public void setArtistDao(ArtistDAO artistDao) 
{
  this.artistDao = artistDao;
}
怼怹恏 2024-10-18 22:24:02

我遇到了同样的问题,但从未设法让代码与 @Configurable 和 @Autowired 一起使用。我最终决定自己编写一个方面来处理 @Configurable 和 @Autowired 注释。代码如下:

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

@SuppressWarnings( "rawtypes" )
@Aspect
public class AutoInjectDependecyAspect implements ApplicationContextAware {
    private static final Logger LOGGER = Logger.getLogger( AutoInjectDependecyAspect.class );

    private ApplicationContext  applicationContext = null;

    @Pointcut( "execution(  (@org.springframework.beans.factory.annotation.Configurable *).new())" )
    public void constructor() {
    }

    @Before( "constructor()" )
    public void injectAutoWiredFields( JoinPoint aPoint ) {
        Class theClass = aPoint.getTarget().getClass();
        try{
            Field[] theFields = theClass.getDeclaredFields();
            for ( Field thefield : theFields ) {
                for ( Annotation theAnnotation : thefield.getAnnotations() ) {
                    if ( theAnnotation instanceof Autowired ) {
                        // found a field annotated with 'AutoWired'
                        if ( !thefield.isAccessible() ) {
                            thefield.setAccessible( true );
                        }

                        Object theBean = applicationContext.getBean( thefield.getType() );
                        if ( theBean != null ) {
                            thefield.set( aPoint.getTarget(), theBean );
                        }
                    }
                }
            }
        } catch ( Exception e ) {
            LOGGER.error( "An error occured while trying to inject bean on mapper '" + aPoint.getTarget().getClass() + "'", e );
        }

    }

    @Override
    public void setApplicationContext( ApplicationContext aApplicationContext ) throws BeansException {
        applicationContext = aApplicationContext;
    }

}

接下来在 spring 上下文中定义切面,以便将 springcontext 注入到切面中

<bean class="[package_name].AutoInjectDependecyAspect" factory-method="aspectOf"/>

I had the same problem and never managed to get the code working with @Configurable and @Autowired. I finally decided to write an aspect myself which would handle the @Configurable and @Autowired annotations. Here is the code:

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

@SuppressWarnings( "rawtypes" )
@Aspect
public class AutoInjectDependecyAspect implements ApplicationContextAware {
    private static final Logger LOGGER = Logger.getLogger( AutoInjectDependecyAspect.class );

    private ApplicationContext  applicationContext = null;

    @Pointcut( "execution(  (@org.springframework.beans.factory.annotation.Configurable *).new())" )
    public void constructor() {
    }

    @Before( "constructor()" )
    public void injectAutoWiredFields( JoinPoint aPoint ) {
        Class theClass = aPoint.getTarget().getClass();
        try{
            Field[] theFields = theClass.getDeclaredFields();
            for ( Field thefield : theFields ) {
                for ( Annotation theAnnotation : thefield.getAnnotations() ) {
                    if ( theAnnotation instanceof Autowired ) {
                        // found a field annotated with 'AutoWired'
                        if ( !thefield.isAccessible() ) {
                            thefield.setAccessible( true );
                        }

                        Object theBean = applicationContext.getBean( thefield.getType() );
                        if ( theBean != null ) {
                            thefield.set( aPoint.getTarget(), theBean );
                        }
                    }
                }
            }
        } catch ( Exception e ) {
            LOGGER.error( "An error occured while trying to inject bean on mapper '" + aPoint.getTarget().getClass() + "'", e );
        }

    }

    @Override
    public void setApplicationContext( ApplicationContext aApplicationContext ) throws BeansException {
        applicationContext = aApplicationContext;
    }

}

Next in your spring context define the aspect so that the springcontext will be injected into the aspect

<bean class="[package_name].AutoInjectDependecyAspect" factory-method="aspectOf"/>
梦里南柯 2024-10-18 22:24:02

也许使用 @Repository DAO 的注释就可以了。

Perhaps using the @Repository annotation for the DAO will do it.

匿名。 2024-10-18 22:24:02

尝试:@Configurable(autowire=Autowire.BY_TYPE)。自动连线默认为关闭:<

try : @Configurable(autowire=Autowire.BY_TYPE). Autowired defaults to off :<

沫雨熙 2024-10-18 22:24:02

我有一个类似的问题,今天解决了。重要的是您需要启用加载时编织并确保加载适当的aspectj 类。在您的 pom.xml 中,您需要添加 aspectjweaver 工件

...
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.6.12</version>
</dependency>
....

您可以更改版本,如果你需要。然后,我将使用 application-context.xml 中的 xsd 路由而不是 DTD 路由:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!--Scans the classpath for annotated components @Component, @Repository, @Service, and @Controller -->
    <context:component-scan base-package="your.base.package"/>
    <!--Activates @Required, @Autowired, @PostConstruct, @PreDestroy and @Resource -->
    <context:annotation-config/>
    <!--This switches on the load-time weaving for @Configurable annotated classes -->
    <context:load-time-weaver/>

</beans>

I had a similar issue that I resolved today. The important thing is that you need to enable load-time weaving and make sure the appropriate aspectj classes are loaded. In your pom.xml you need to add the aspectjweaver artifact:

...
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.6.12</version>
</dependency>
....

You can change the version if you need to. Then, I would go the xsd route in you application-context.xml instead of the DTD route:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!--Scans the classpath for annotated components @Component, @Repository, @Service, and @Controller -->
    <context:component-scan base-package="your.base.package"/>
    <!--Activates @Required, @Autowired, @PostConstruct, @PreDestroy and @Resource -->
    <context:annotation-config/>
    <!--This switches on the load-time weaving for @Configurable annotated classes -->
    <context:load-time-weaver/>

</beans>
双手揣兜 2024-10-18 22:24:02

另外,请验证您的 AspectJ 版本是否是最新的。我浪费了几个小时来尝试完成这项工作,原因是 Aspectjweaver.jar 的旧版本。我更新到 1.7.2,一切都很顺利。

Also, please verify that your version of AspectJ is current. I wasted a few hours trying to make this work, and the cause was an old version of Aspectjweaver.jar. I updated to 1.7.2 and everything worked like a charm.

窗影残 2024-10-18 22:24:02

@Configurable 和 LTW 存在错误。如果您在任何方法中使用您的类作为参数,自动连接就会停止工作。
https://jira.spring.io/plugins/servlet/mobile#issue /SPR-8502

There is a bug with @Configurable and LTW. If you use your class as a parameter in any method the auto wiring stops working.
https://jira.spring.io/plugins/servlet/mobile#issue/SPR-8502

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文