目录
1.存储 Bean 对象
1.1 前置⼯作:配置扫描路径
1.2 添加注解存储 Bean 对象
1.2.1 @Controller(控制器存储)
1.2.2 @Service(服务存储)
1.2.3 @Repository(仓库存储)
1.2.4 @Component(组件存储)
1.2.5 @Configuration(配置存储)
1.3 为什么要这么多类注解?
1.3.1 类注解之间的关系
1.3.2 Bean 命名规则
1.4 方法注解 @Bean
1.4.1 ⽅法注解要配合类注解使⽤
1.4.2 重命名 Bean
2.获取 Bean 对象(对象装配)
2.1 属性注入
2.2 构造方法注入
2.3 Setter 注入
2.4 三种注入优缺点分析
2.5 @Resource:另⼀种注⼊关键字
@Autowired 和 @Resource 的区别
2.6 同⼀类型多个 @Bean 报错
总结
1.存储 Bean 对象
1.1 前置⼯作:配置扫描路径
<?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:content="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><content:component-scan base-package="org.example"></content:component-scan>
</beans>
1.2 添加注解存储 Bean 对象
- 类注解:@Controller、@Service、@Repository、@Component、@Configuration。
- ⽅法注解:@Bean。
1.2.1 @Controller(控制器存储)
@Controller // 将对象存储到 Spring 中
public class UserController {public void sayHi(String name) {System.out.println("Hi," + name);}
}
public class App {public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");// 2.得到 beanUserController userController = (UserController) context.getBean("userController");// 3.调⽤ bean ⽅法userController.sayHi("zhangsan");}
}
1.2.2 @Service(服务存储)
@Service
public class UserService {public void sayHi(String name) {System.out.println("Hi," + name);}
}
public class App {public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");// 2.得到 beanUserService userService = (UserService) context.getBean("userService");// 3.调⽤ bean ⽅法userService.sayHi("lisi");}
}
1.2.3 @Repository(仓库存储)
@Repository
public class UserRepository {public void sayHi(String name) {System.out.println("Hi," + name);}
}
public class App {public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");// 2.得到某个 beanUserRepository userRepository = (UserRepository) context.getBean("userRepository");// 3.调⽤ bean ⽅法userRepository.sayHi("zhangsan");}
}
1.2.4 @Component(组件存储)
使⽤ @Component 存储 bean 的代码如下所示:
@Component
public class UserComponent {public void sayHi(String name) {System.out.println("Hi," + name);}
}
public class App {public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");// 2.得到某个 beanUserComponent userComponent = (UserComponent) context.getBean("userComponent");// 3.调⽤ bean ⽅法userComponent.sayHi("lisi");}
}
1.2.5 @Configuration(配置存储)
@Configuration
public class UserConfiguration {public void sayHi(String name) {System.out.println("Hi," + name);}
}
public class App {public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");// 2.得到某个 beanUserConfiguration userConfiguration = (UserConfiguration) context.getBean("userConfiguration");// 3.调⽤ bean ⽅法userConfiguration.sayHi("Bit");}
}
1.3 为什么要这么多类注解?
- @Controller:表示的是业务逻辑层;
- @Servie:服务层;
- @Repository:持久层;
- @Configuration:配置层。
1.3.1 类注解之间的关系
1.3.2 Bean 命名规则
但是,当我们⾸字⺟和第⼆个字⺟都是⼤写时,就不能正常读取到 bean 了,如下图所示:
顺藤摸⽠,我们最后找到了 bean 对象的命名规则的⽅法:
它使⽤的是 JDK Introspector 中的 decapitalize ⽅法,源码如下:
public static String decapitalize(String name) {if (name == null || name.length() == 0) {return name;}// 如果第⼀个字⺟和第⼆个字⺟都为⼤写的情况,是把 bean 的⾸字⺟也⼤写存储了if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&Character.isUpperCase(name.charAt(0))){return name;}// 否则就将⾸字⺟⼩写char chars[] = name.toCharArray();chars[0] = Character.toLowerCase(chars[0]);return new String(chars);
}
1.4 方法注解 @Bean
public class Users {@Beanpublic User user1() {User user = new User();user.setId(1);user.setName("Java");return user;}
}
public class App2 {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");User user = (User) context.getBean("user1");System.out.println(user.toString());}
}
1.4.1 ⽅法注解要配合类注解使⽤
@Component
public class Users {@Beanpublic User user1() {User user = new User();user.setId(1);user.setName("Java");return user;}
}
1.4.2 重命名 Bean
@Component
public class Users {@Bean(name = {"u1"})public User user1() {User user = new User();user.setId(1);user.setName("Java");return user;}
}
class App {public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");// 2.得到某个 beanUser user = (User) context.getBean("u1");// 3.调⽤ bean ⽅法System.out.println(user);}
}
2.获取 Bean 对象(对象装配)
- 属性注⼊
- 构造⽅法注⼊
- Setter 注⼊
2.1 属性注入
@Service
public class UserService {/*** 根据 ID 获取⽤户数据** @param id* @return*/public User getUser(Integer id) {// 伪代码,不连接数据库User user = new User();user.setId(id);user.setName("Java-" + id);return user;}
}
@Controller
public class UserController {// 注⼊⽅法1:属性注⼊@Autowiredprivate UserService userService;public User getUser(Integer id) {return userService.getUser(id);}
}
public class UserControllerTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");UserController userController = context.getBean(UserController.class);System.out.println(userController.getUser(1).toString());}
}
2.2 构造方法注入
@Controller
public class UserController2 {// 注⼊⽅法2:构造⽅法注⼊private UserService userService;@Autowiredpublic UserController2(UserService userService) {this.userService = userService;}public User getUser(Integer id) {return userService.getUser(id);}
}
如果只有⼀个构造⽅法,那么 @Autowired 注解可以省略
但是如果类中有多个构造⽅法,那么需要添加上 @Autowired 来明确指定到底使⽤哪个构造⽅法,否则程序会报错
2.3 Setter 注入
@Controller
public class UserController3 {// 注⼊⽅法3:Setter注⼊private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public User getUser(Integer id) {return userService.getUser(id);}
}
2.4 三种注入优缺点分析
属性注⼊
- 优点是简洁,使⽤⽅便;
- 缺点是只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,并且只有在使⽤的时候才会出现 NPE(空指针异常)。不能注入一个final修饰的属性。
构造⽅法注⼊
- 优点是可以注入final修饰的属性,注入的对象不会被修改,依赖对象在使用前一定会被完全初始化,通用性好
- 缺点是如果有多个注⼊会显得⽐较臃肿,但出现这种情况你应该考虑⼀下当前类是否符合程序的单⼀职责的设计模式了
Setter 注入
- 优点是方便再类实例之后,重新对该对象进行配置或注入
-
不能注入一个final修饰的属性;注入对象可能会被改变,因为setter方法可能会被多次调用,就有被修改的风险
补充:
final修饰的属性,需要具备下列两个条件之一:
2.5 @Resource:另⼀种注⼊关键字
@Controller
public class UserController {// 注⼊@Resourceprivate UserService userService;public User getUser(Integer id) {return userService.getUser(id);}
}
@Autowired 和 @Resource 的区别
- 出身不同:@Autowired 来⾃于 Spring,⽽ @Resource 来⾃于 JDK 的注解;
- 使⽤时设置的参数不同:相⽐于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如 name设置,根据名称获取 Bean。
- @Autowired 可⽤于 Setter 注⼊、构造函数注⼊和属性注⼊,⽽ @Resource 只能⽤于 Setter 注⼊和属性注⼊,不能⽤于构造函数注⼊。
2.6 同⼀类型多个 @Bean 报错
@Component
public class Users {@Beanpublic User user1() {User user = new User();user.setId(1);user.setName("Java");return user;}@Beanpublic User user2() {User user = new User();user.setId(2);user.setName("MySQL");return user;}
}
@Controller
public class UserController4 {// 注⼊@Resourceprivate User user;public User getUser() {return user;}
}
报错的原因是,⾮唯⼀的 Bean 对象。
- 使⽤ @Resource(name="user1") 定义。
- 使⽤ @Qualifier 注解定义名称。
@Controller
class UserController4 {// 注⼊@Resource(name = "user1")private User user;public User getUser() {return user;}
}
@Controller
public class UserController5 {// 注⼊@Autowired@Qualifier(value = "user2")private User user;public User getUser() {return user;}
}