Spring-JPA @Transactional导致错误。为什么添加@EnableAspectJAutoProxy(proxyTargetClass = true)修复它?

时间:2017-09-09 10:29:34

标签: spring spring-data-jpa

问题:我正在设置Spring + JPA + MYSQL数据库。但是,一旦我进行了设置,我总会收到以下错误:

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'lt.robot.dao.UserJPADaoImpl' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:353)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1090)
at lt.robot.main.App.main(App.java:15)

此问题已解决here。 因为我的配置文件是用Java编写的,所以我添加了注释(如下所示),现在它可以正常工作。

  

@EnableAspectJAutoProxy(proxyTargetClass = true)

问题:为什么需要它?我已经看过" Spring in Action第4版"," Spring Data",众多在线教程,但没有一个用AspectJProxy注释Config类。我的应用程序设置与在线发现的不同(甚至是Spring的github示例)。

我的设置

包结构:

lt.robot.main
         App.class
         AppConfig.class
lt.robot.entity
         User.class
lt.robot.dao
         UserJPADao.interface
         UserJPADaoImpl.class

pom.xml依赖项

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.spring.platform</groupId>
            <artifactId>platform-bom</artifactId>
            <version>Brussels-SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>


<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <version>1.5.0.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
    </dependency>
</dependencies>

App.class

import lt.robot.dao.UserJPADaoImpl;
import lt.robot.entity.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App 
{
    public static void main( String[] args )
    {
        ApplicationContext ctx = 
            new AnnotationConfigApplicationContext(AppConfig.class);

        UserJPADaoImpl userDaoImpl = ctx.getBean(UserJPADaoImpl.class);

        System.out.println(userDaoImpl.get(2));

        User userNew = new User();
        userNew.setUser_name("NewUser");
        userDaoImpl.add(userNew);
   }
}

AppConfig.class

@Configuration
@EnableTransactionManagement
@ComponentScan("lt.robot")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {

    @Bean
    public DataSource getDataSource() {

        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/spring1");
        dataSource.setUsername("root");
        dataSource.setPassword("pass");
        return dataSource;
    }


    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(){

        HibernateJpaVendorAdapter vendorAdapter = new 
            HibernateJpaVendorAdapter();
        vendorAdapter.setDatabase(Database.MYSQL);
        vendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factory = 
                new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("lt.robot.entity");
        factory.setDataSource(getDataSource());
        return factory;
    }

    @Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager(){
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return txManager;
    }
}

User.class

@Entity
@Table(name = "user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private int user_id;

    @Column(name = "user_name")
    private String user_name;
    //Getters & Setters
}

UserJPADaoImpl.class

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import lt.robot.dao.UserJPADao;
import lt.robot.entity.User;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional(transactionManager = "transactionManager")
public class UserJPADaoImpl implements UserJPADao {

    @PersistenceContext
    private EntityManager em;

    public void add(User t) {
        em.persist(t);
    }

    public User get(int id) {
        return em.find(User.class, id);
    }
}

2 个答案:

答案 0 :(得分:1)

你的答案是herehere bean使用的bean代理机制

由于UserJPADaoImpl类被标记为@Transactional,因此在创建接口UserJPADao时会为其创建基于JDK接口的默认代理。

语句ctx.getBean(UserJPADaoImpl.class)表示Spring专门查找UserJPADaoImpl类型的bean而不是UserJPADao;这是默认创建的,如上所述。

因此,Spring应用程序上下文找不到任何类型UserJPADaoImpl的bean,并遇到以下异常。

  

线程中的异常&#34; main&#34; org.springframework.beans.factory.NoSuchBeanDefinitionException:没有类型&#39; lt.robot.dao的限定bean。 UserJPADaoImpl &#39;可用

因此,要向Spring发出信号以查找特定的bean类型,您可以使用以下任何一种

  • 而不是通过ctx.getBean(UserJPADaoImpl.class)查找实现类的bean查找它的接口类型bean UserJPADao来自ctx.getBean(UserJPADao.class)
  • 告诉Spring使用基于CGLIB类的代理而不是默认的基于JDK接口的代理(如果实现类仅需要bean查找) - 这是您通过注释@EnableAspectJAutoProxy(proxyTargetClass = true)
  • 所做的

主要是在教程中使用了第一种方法,因为你没有看到@EnableAspectJAutoProxy(proxyTargetClass = true)的任何提及,因为它们依赖于基于默认JDK接口的代理和通过接口而不是其实现的bean查找。 / p>

如果您需要任何进一步的信息,请在评论中说明。

答案 1 :(得分:0)

由于您使用的是Spring-Data-JPA,我建议您使用JPARepository inteface创建存储库,如下所示:

@Repository
public interface UserRepository extends JpaRepository<User, Serializable>{
    User findByUser_id(int id); 
}

在您的数据库配置中使用@EnableJpaRepositories

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.repository")
public class AppConfig {
    ..
    ..
    ..
}

创建服务,然后像这样自动装配UserRepository并使用其方法。

@Service
public class UserService {
    @Autowired
    UserRepository userRepository;

    public User saveUser(User user){
        return userRepository.save(user);
    }

    public List<User> getAllUsers(){
        return userRepository.getAll();
    }

    public User getUserById(int id){
        return userRepository.findByUser_id(id);
    }

}

创建一个控制器并自动装配UserService并使用其方法。