IOC 入门案例
引入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
创建接口及其配置类
public interface AccountService {
void saveAccount();
}
@Service("accountService") // 把当前类对象存入Spring容器中
public class AccountServiceImpl implements AccountService {
@Override
public void saveAccount() {
System.out.println("调用了 AccountServiceImpl 的 save 方法");
}
}
配置类及其测试方法
import com.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration // 指定当前类是一个配置类
// 通过注解指定spring在创建容器时要扫描的包
// basePackages的作用是一样的。我们使用此注解就等同在 xml中配置了 <context:component-scan base-package=“com”/>
@ComponentScan(basePackages = "com")
public class ApplicationTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationTest.class);
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
accountService.saveAccount();
}
}
测试结果
创建 bean
的注解
测试所需要的两个实例对象
public class Woman {
private String name;
private int age;
// 需要的构造方法 Getter / Setter toString() 自行补充
}
import java.util.Date;
public class Person {
private String name;
private int age;
// 需要的构造方法 Getter / Setter toString() 自行补充
}
注解 | 作用 |
---|---|
@Component | 把当前类对象存入 Spring 容器中 |
@Controller | 把当前类对象存入 Spring 容器中,一般用于表现层 |
@Service | 把当前类对象存入 Spring 容器中,一般用在业务层 |
@Repository | 把当前类对象存入 Spring 容器中,一般用在持久层 |
@Bean | 把当前方法的返回值作为 bean 对象存入 Spring 容器中 |
@import | 允许导入 @Configuration 类, ImportSelector 和 ImportBeanDefinitionRegistrar 的具体实现, 以及常规组件类 |
方式一:使用 @Component
@Controller
@Service
@Repository
// 说明:这个四个注解的使用方式有一样,使用在类上,表示将当前类对象存入 Spring 容器中,相当于 XML 配置中的 <bean id="" class="">
// 这个注解有一个属性 value ,用于指定 bean 的 id,若不写默认值是当前类名且首字母小写
@Service("accountService") // 把当前类对象存入Spring容器中,并且 bean 的id名为 accountService
public class AccountServiceImpl implements AccountService {
@Override
public void saveAccount() {
System.out.println("调用了 AccountServiceImpl 的 save 方法");
}
}
方式二:使用 @Bean
情况一:@Bean
在配置类中使用
//问题一:什么是配置类
// ① 配置是有注解 @Configuration
// ② 若 ① 不存在,那么就看AnnotationConfigApplicationContext 中的参数是哪个类
//细节点:
//使用 @Bean 配置方法时,如果方法有参数,Spring 框架会容器中查找有没有可用的 bean 对象,查找的方式和Autowired注解是一样的
@Configuration
@ComponentScan(basePackages = "com")
public class ApplicationTest {
@Bean
public Woman getWoman(){
return new Woman("香香",22);
}
@Bean
public Person getPerson(){
return new Person("李四",15);
}
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationTest.class);
// 测试 @Bean
Person person = (Person) applicationContext.getBean("getPerson");
System.out.println(person);
}
}
测试结果:
情况二:@Bean
没有在配置类中使用
import com.domain.Person;
import org.springframework.context.annotation.Bean;
public class InstanceFactory {
@Bean
public Person getPerson(){
String name = "李四";
int age = 15;
return new Person(name,age);
}
}
@Configuration
@ComponentScan(basePackages = "com")
@Import(InstanceFactory.class) // 使用 @Import 注解将含有 @Bean 注解的类导进来
public class ApplicationTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationTest.class);
// 测试@ Bean
Person person = (Person) applicationContext.getBean("getPerson");
System.out.println(person);
}
}
方式三:使用 @Import 注解
@Configuration
@ComponentScan(basePackages = "com")
@Import(InstanceFactory.class) // 使用了该注解进行导入之后,那么导入的类也会加入到容器中
public class ApplicationTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationTest.class);
// 测试 @Import
InstanceFactory factory = applicationContext.getBean(InstanceFactory.class);
System.out.println(factory); // 输出:com.factory.InstanceFactory@53bd8fca
}
}
方式四:实现 FactoryBean 接口
import com.domain.Woman;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.support.FactoryBeanRegistrySupport;
public class WomanFactoryBean implements FactoryBean<Woman> {
// 返回该FactoryBean“生产”的对象实例,我们需要实现该方法以给出自己的对象实例化逻辑
@Override
public Woman getObject() throws Exception {
return new Woman("Mary",15);
}
// 方法仅返回getObject()方法所返回的对象的类型,如果预先无法确定,则返回null
@Override
public Class<?> getObjectType() {
return Woman.class;
}
}
@Configuration
@ComponentScan(basePackages = "com")
public class ApplicationTest {
@Bean
public WomanFactoryBean womanFactoryBean(){
return new WomanFactoryBean();
}
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationTest.class);
// 实现 FactoryBean 接口
// 默认获取到的是工厂bean调用getObject创建的对象
Object woman1 = applicationContext.getBean("womanFactoryBean");
System.out.println(woman1); // 结果:Woman{name='Mary', age=15}
// 要获取工厂Bean本身,我们需要给id前面加一个&
Object woman2 = applicationContext.getBean("&womanFactoryBean");
System.out.println(woman2); // 结果:com.factory.WomanFactoryBean@1cdc4c27
}
}
方法五:实现 BeanFactoryPostProcessor 接口
import com.domain.Woman;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
@Component // 将当前类加入 Spring 容器中
public class PostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 通过次方法注册 bean 并方法 Spring 容器
beanFactory.registerSingleton("woman",new Woman("李四",15));
}
}
@Configuration
@ComponentScan(basePackages = "com")
public class ApplicationTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationTest.class);
// 测试
Woman woman = applicationContext.getBean("woman",Woman.class);
System.out.println(woman); // 结果:Woman{name='李四', age=15}
}
}
注入数据的注解
注解 | 作用 |
---|---|
@AutoWired | 按照类型自动注入 |
@Qualifier | 在按照类型注入的基础之上再按照名称注入;它在给类成员注入时不能单独使用;但是在给方法参数注入时可以 |
@Resource | 直接按照 bean 的 id 注入,它可以独立使用 |
@Value | 用于注入基本类型和 String 类型的数据 |
@PropertySource | 用于指定 properties 文件的位置 |
**注意点:**前三个注解都只能注入其他 bean
类型的数据。基本类型和 String
类型无法使用上述注解实现。集合类型的注入只能通过 XML
来实现
@AutoWired
注解的使用:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component // 1. 将该类放在 Spring 容器中
public class Man {
@Autowired // 2. 注解使用在属性上:表示 Spring 容器会自动注入值
private Person person;
// 3. 注解使用在方法上:表示 Spring 容器会在类加载后自动注入这个方法的参数,并执行一遍方法。
@Autowired
public void showPerson(Person person){
System.out.println(person);
}
// 需要的构造方法 Getter / Setter toString() 自行补充
}
import org.springframework.stereotype.Component;
@Component // 将该类放在 Spring 容器中
public class Person {
private String name = "李四";
private int age = 15;
// 需要的构造方法 Getter / Setter toString() 自行补充
}
@Configuration
@ComponentScan(basePackages = "com")
public class ApplicationTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationTest.class);
//测试 @Autowired
Man man = applicationContext.getBean(Man.class);
System.out.println(man);
}
}
@Qualifier
注解的使用
@Configuration
@ComponentScan(basePackages = "com")
public class ApplicationTest {
// 向 Spring 容器中加入两个 Person 对象
@Bean(value = "p1")
public Person person1(){
return new Person("李四",22);
}
@Bean(value = "p2")
public Person person2(){
return new Person("李四",23);
}
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationTest.class);
//测试 A
Man man = applicationContext.getBean(Man.class);
System.out.println(man);
}
}
@Component
public class Man {
@Autowired
private Person person;
@Autowired
public void showPerson(Person person){
System.out.println(person);
}
}
由于 @Autowired
是按照类型注入,所以在该案例中,Spring
容器中有两个 Person
对象,则使用 @Autowired
会报错
当容器中有多个需要注入类型得对象时,结合使用 @Qualifier
@Component
public class Man {
// @Qualifier 的 value 属性用于指定注入 bean 的 id
@Autowired
@Qualifier(value = "p1")
private Person person;
@Autowired
@Qualifier(value = "p2")
public void showPerson(Person person){
System.out.println(person);
}
}
@Resource
注解的使用
在上述使用 @Autowire
报错得案例中,不仅可以使用 @Autowire
和 @Qualifier
组合起来使用,还可以使用 @Resorece
根据 bean
得 id
值进行注入
@Component
public class Man {
// @Resource 的 name属性用于指定 bean 的 id
@Resource(name = "p1")
private Person person;
@Resource(name = "p2")
public void showPerson(Person person){
System.out.println(person);
}
}
@Value
注解的使用
使用方式一:直接注入 String
或基本数据类型
@Component
public class Person {
@Value(value = "李四")
private String name;
@Value(value = "20")
private int age;
}
@Configuration
@ComponentScan(basePackages = "com")
public class ApplicationTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationTest.class);
// 测试 Value
Person person = applicationContext.getBean("person",Person.class);
System.out.println(person);
}
}
测试结果:
使用方式二:注入 properties
文件的值
name=张三
age=50
@Component
// 该注解用于指定properties文件的位置
// value属性指定文件的名称和路径关键字
// classpath 表示类路径下
// encoding 表示该文件使用 utf-8 编码,不然结果会出现乱码
@PropertySource(value = "classpath:person.properties",encoding = "utf-8")
public class Person {
@Value(value = "${name}")
private String name;
@Value(value = "${age}")
private int age;
}
@Configuration
@ComponentScan(basePackages = "com")
public class ApplicationTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationTest.class);
// 测试 Value
Person person = applicationContext.getBean("person",Person.class);
System.out.println(person);
}
}
注意点:我在使用 IDEA
的时候加上了 encoding
还是出现了乱码;其解决方案如下:
其他常用注解说明
注解 | 说明 |
---|---|
@Scope | 用于指定 bean 的作用范围;作用和 bean 标签中使用 scope 属性实现的功能是一样的 |
@PreDestroy | 用于指定销毁方法;作用和在 bean 标签中使用 destroy-method 的作用是一样的 |
@PostConstruct | 用于指定初始化方法;作用和在 bean 标签中使用 init-method 作用是一样的 |
@Configuration | 指定当前类是一个配置类;配置类作为 AnnotationConfigApplicationContext 对象创建的参数时,该注解可以不写 |
@ComponentScan | 用于指定 Spring 在创建容器时要扫描的包; |
有问题可加QQ群一起交流:1076386005