spring exception--No unique bean of type

今天碰到一个问题,就是我现有项目需要加一个定时器任务,我的代码如下:
<!-- 每日数据同步 总数监测任务******************begin -->

	<bean id="dataMonitorServiceImpl"
		class="com.netqin.function.dataMonitor.service.impl.DataMonitorServiceImpl">
	</bean>
	<bean id="scheduledDataMonitorDetail"
		class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<property name="targetObject">
			<ref bean="dataMonitorServiceImpl" />
		</property>
		<property name="targetMethod">
			<value>autoMonitorSyncStatus</value>
		</property>
	</bean>
	<bean id="dataMonitorCronReportTrigger"
		class="org.springframework.scheduling.quartz.CronTriggerBean">
		<property name="jobDetail">
			<ref bean="scheduledDataMonitorDetail" />
		</property>
		<property name="cronExpression">
			<value>0 41 10 * * ?</value>
		</property>
	</bean>
	<!-- 每日数据同步 总数监测任务******************end -->

这里我初始化了一个叫:dataMonitorServiceImpl的bean,这个bean是一个现有Service的实现类。

@Service
public class DataMonitorServiceImpl implements IDataMonitorService {
	Logger logger = Logger.getLogger(DataMonitorServiceImpl.class);
	@Autowired
	private IBaseDao dao;
	@Autowired
	private IDasBaseDao dasDao;
如上所示,我这里是用了注解@Service,spring会自动加载这个类,

因为上面我对这个bean有定义了一次,理论上来说会报错,因为同一个bean加载了两次,那么当向IDataMonitorService注入的时候就会发现有两个DataMonitorServiceImpl的bean,

但是我想想中的报错场景并没有发生,tomcat正常启动,我就很想知道为什么。

我把xml里面定义bean的名字改了一下,第一个字母改成大写,重启tomcat,ok,我看见了我想看见的错误:

No unique bean of type [com.netqin.function.dataMonitor.service.IDataMonitorService] is defined: expected single matching bean but found 2: [dataMonitorServiceImpl, DataMonitorServiceImpl]
很明显,后边那个bean是我在xml里面声明的,那么第一个就是我用annotation的@Service声明的,这就是说明

1. @Service在声明bean的时候如果不指定名称的话,会默认以类名的一个字母小写命名。

2. 当spring初始化bean时,会监测要初始化的bean是否已经存在相同名称的bean。

做出上面的两个结论之后,我又有了俩个疑问,

1. bean在初始化的时候,xml声明和annotation的声明初始化bean的先后顺序是怎么样的。

2. bean在监测是否有相同名称的bean的时候,是只检测名称一致性,还是说是在每个bean的类别下的名称一致性?

第一个问题的答案是这样的,他们的初始化的顺序是有你指定的xml所决定的,举个例子:

你在applicationcontext.xml(这里只是举例)里显示声明了annotation需要扫描的文件目录包括那些,然后接在在下面又声明了很多bean,这种情况就是先初始化annotation,在初始化xml生命的bean。

spring是依据你声明的顺序来初始化一切,spring会从最原始的spring的xml文件开始扫描,扫描一条处理一条,也可能你的spring又引用了很多别的xml配置,那也是一样的,看引入的先后顺序。

第二个问题我做了如下的实验,:

<bean id="dataMonitorServiceImpl"         	
		class="com.netqin.function.channel.service.impl.ChannelManagementServiceImpl">
	</bean>
	<!-- <bean id="dataMonitorServiceImpl"
		class="com.netqin.function.dataMonitor.service.impl.DataMonitorServiceImpl">
	</bean> -->
原先的bean我注释掉了 我换了一个,但是bean名字没变,

public DataMonitorServiceImpl(){
		System.out.println("DataMonitorServiceImpl is loaded!");
	}
我给DataMonitorServiceImpl写了一个空的构造方法,已确定他是否已经被spring装载。

ok,看看tomcat说什么:

 No unique bean of type [com.netqin.function.dataMonitor.service.IDataMonitorService] is defined: Unsatisfied dependency of type [interface com.netqin.function.dataMonitor.service.IDataMonitorService]: expected at least 1 matching bean
spring说没有这个类型的bean被定义,这个类型的bean被期望的是最少有一个匹配的bean。

第二个问题的答案就是spring在初始化bean的时候是只保持名称的一致性,这个其实和xml里面声明bean的时候bean不能重复是一致的,多了annotation也不影响。

总结一下今天的结论:

1. @Service在声明bean的时候如果不指定名称的话,会默认以类名的一个字母小写命名。

2. 当spring初始化bean时,会监测要初始化的bean是否已经存在相同名称的bean。

3. spring初始化bean的顺序依赖于你在xml里面配置的顺序。

4.spring在初始化bean的时候是只保持名称的一致性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 Java Spring 项目案例,实现了用户注册、登录和资料修改功能: 1. 首先,你需要创建一个新的 Maven 项目。在 pom.xml 文件中添加以下依赖: ```xml <dependencies> <!-- Spring Framework --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.9</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.3.9</version> </dependency> <!-- Spring Security --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>5.5.1</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.5.1</version> </dependency> <!-- Thymeleaf --> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.0.12.RELEASE</version> </dependency> <!-- MySQL数据库 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> </dependency> <!-- Servlet API --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> </dependencies> ``` 2. 创建数据库表 创建一个名为 `users` 的表,用来存储用户信息。表结构如下: ``` CREATE TABLE `users` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `username` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, `email` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` 3. 创建实体类 创建一个名为 `User` 的实体类,用来映射 `users` 表。 ```java @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, unique = true) private String username; @Column(nullable = false) private String password; @Column(nullable = false) private String email; // 省略 getter 和 setter } ``` 4. 创建 DAO 接口 创建一个名为 `UserRepository` 的接口,继承 `JpaRepository` 接口,用来对 `users` 表进行 CRUD 操作。 ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { User findByUsername(String username); } ``` 5. 创建 Service 接口和实现类 创建一个名为 `UserService` 的接口,定义注册、登录和资料修改等方法。 ```java public interface UserService { void register(User user); UserDetails login(String username, String password); void updateProfile(User user); } ``` 创建一个名为 `UserServiceImpl` 的实现类,实现 `UserService` 接口。 ```java @Service public class UserServiceImpl implements UserService, UserDetailsService { @Autowired private UserRepository userRepository; @Autowired private PasswordEncoder passwordEncoder; @Override public void register(User user) { user.setPassword(passwordEncoder.encode(user.getPassword())); userRepository.save(user); } @Override public UserDetails login(String username, String password) { User user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("User not found"); } if (!passwordEncoder.matches(password, user.getPassword())) { throw new BadCredentialsException("Invalid username or password"); } return new UserPrincipal(user); } @Override public void updateProfile(User user) { userRepository.save(user); } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("User not found"); } return new UserPrincipal(user); } } ``` 6. 创建控制器 创建一个名为 `UserController` 的控制器,用来处理用户注册、登录和资料修改等请求。 ```java @Controller public class UserController { @Autowired private UserService userService; @GetMapping("/register") public String showRegistrationForm(Model model) { model.addAttribute("user", new User()); return "register"; } @PostMapping("/register") public String register(@ModelAttribute("user") @Valid User user, BindingResult result) { if (result.hasErrors()) { return "register"; } userService.register(user); return "redirect:/login"; } @GetMapping("/login") public String showLoginForm() { return "login"; } @PostMapping("/login") public String login(@RequestParam String username, @RequestParam String password) { userService.login(username, password); return "redirect:/profile"; } @GetMapping("/profile") public String showProfileForm(Authentication authentication, Model model) { User user = ((UserPrincipal) authentication.getPrincipal()).getUser(); model.addAttribute("user", user); return "profile"; } @PostMapping("/profile") public String updateProfile(@ModelAttribute("user") @Valid User user, BindingResult result) { if (result.hasErrors()) { return "profile"; } userService.updateProfile(user); return "redirect:/profile"; } } ``` 7. 创建安全配置类 创建一个名为 `WebSecurityConfig` 的类,用来配置 Spring Security。 ```java @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/register", "/login").permitAll() .antMatchers("/profile").authenticated() .and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/profile") .and() .logout() .logoutSuccessUrl("/login") .and() .csrf() .disable(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService).passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` 8. 创建 Thymeleaf 模板 在 `src/main/resources/templates` 目录下创建以下模板文件: register.html ```html <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Register</title> </head> <body> <h1>Register</h1> <form th:action="@{/register}" th:object="${user}" method="post"> <div> <label for="username">Username:</label> <input type="text" id="username" th:field="*{username}" required> <span th:if="${#fields.hasErrors('username')}" th:errors="*{username}"></span> </div> <div> <label for="password">Password:</label> <input type="password" id="password" th:field="*{password}" required> <span th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></span> </div> <div> <label for="email">Email:</label> <input type="email" id="email" th:field="*{email}" required> <span th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></span> </div> <div> <button type="submit">Register</button> </div> </form> </body> </html> ``` login.html ```html <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Login</title> </head> <body> <h1>Login</h1> <form th:action="@{/login}" method="post"> <div> <label for="username">Username:</label> <input type="text" id="username" name="username" required> </div> <div> <label for="password">Password:</label> <input type="password" id="password" name="password" required> </div> <div> <button type="submit">Login</button> </div> </form> </body> </html> ``` profile.html ```html <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Profile</title> </head> <body> <h1>Profile</h1> <form th:action="@{/profile}" th:object="${user}" method="post"> <div> <label for="username">Username:</label> <input type="text" id="username" th:field="*{username}" required> <span th:if="${#fields.hasErrors('username')}" th:errors="*{username}"></span> </div> <div> <label for="email">Email:</label> <input type="email" id="email" th:field="*{email}" required> <span th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></span> </div> <div> <button type="submit">Save</button> </div> </form> </body> </html> ``` 9. 运行项目 运行项目,访问 `http://localhost:8080/register` 注册用户,然后访问 `http://localhost:8080/login` 登录,最后访问 `http://localhost:8080/profile` 修改个人资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值