一、搭建项目
创建父项目
创建一个Maven工程:ssm-parent
修改POM
由于这个Maven工程会作为一个父工程,所以把它的打包方式修改为pom
父项目一般是不写代码的,未来可以用来聚合子项目,也可以管理子项目的依赖。
由于父项目不写代码,我们可以把父项目中的src目当删除掉。
创建模块
在父项目上点击右键 -> New -> Module...
创建时选择Spring Initializer,通过它来创建好一个工程的脚手架。
对于创建出来的项目中的一些东西可以删除掉,比如:.mvn .gitgnore HELP.md mvnw mvnw.cmd,只需要保留src目录和pom.xml文件即可。
修改主启动类为如下
@SpringBootApplication
public class Spring01IocApplication {
public static void main(String[] args) {
// 跑起一个spring的应用 ApplicationContext Spring应用上下文对象 IOC容器
ConfigurableApplicationContext ioc = SpringApplication.run(Spring01IocApplication.class, args);
System.out.println("ioc = " + ioc);
}
}
此时我们启动项止并且可以看到打印的信息则说明应用创建好了。
二、IoC容器
创建组件
我们创建组件可以使用@Bean注解,它会把自定义的Bean对象放入到容器当中去(IoC容器,在主方法中我们创建的就是这个容器)
@Bean
public Person person(){
Person person = new Person();
person.setName("张三");
person.setAge(20);
person.setGender("男");
return person;
}
容器中的每一个组件都有自己的名称,这个名称默认就是方法的名称。如果我们要自己指定的话则在@Bean中添加value属性的值来指定。
获取容器中的组件
组件有四大特征:名字、类型、对象、作用域
名称可以在@Bean注解上进行指定,当不指定时它的名称就是方法的名称
// 3、给容器中注册一个组件,容器中的每一个组件都有名字,默认名称是方法名
@Bean("hahaha")
public Person person(){
Person person = new Person();
person.setName("张三");
person.setAge(20);
person.setGender("男");
return person;
}
@Bean("zhangsan")
public Person zhangsan(){
Person person = new Person();
person.setName("张三");
person.setAge(20);
person.setGender("男");
return person;
}
@Bean
public Dog dog() {
return new Dog();
}
public class Person {
private String name;
private int age;
private String gender;
// 省略setter 和 getter
}
public class Dog{
}
根据组件的名称进行获取
// 4.1 按组件名称获取对象
Person zhangsan = (Person) ioc.getBean("hahaha");
System.out.println("hahaha = " + zhangsan);
按照组件的类型获取
// 4.2、按照组件的类型获取对象
// 按照类型获取的好处是不用再做一次强转了
Dog bean = ioc.getBean(Dog.class);
System.out.println("bean = " + bean);
按照组件类型获取所有同类型的对象
// 4.3、按照组件类型获取所有同类型的组件对象
Map<String, Person> beans = ioc.getBeansOfType(Person.class);
System.out.println(beans);
按照名称+类型获取
// 4.4、如果存在某个名字的组件,按名称获取一定是唯一精确指定的那个组件,注意:组件的名称在容器中是唯一的
Person bean = ioc.getBean("hahaha", Person.class);
System.out.println("bean = " + bean);
从容器中获取组件时可能会发生如下的一些异常:
- NoSuchBeanDefinitionException 表示容器中没有指定的组件
- NoUniqueBeanDefinitionException 表示容器中获取组件时不唯一,不明确要返回哪个组件给你
注意:如果我们向容器中放两个同名的组件,容器中最终只会放进去一个,后面放入的那个不会再放进去了!!
Spring容器在启动过程中就会去创建组件,并且创建的组件对象是单例的,并不是在获取时才去创建组件。
每次我们需要使用组件的时候直接去容器中拿的就可以了!
@Configuration注解
前面我们在main方法所在有类使用@Bean来创建组件,这不是一个好习惯,因为这样子会导致main方法所在的类变得臃肿,而main方法所在的类本质上只是一个启动的入口,把创建组件放在这里不太合适。
组件属于应用的配置,我们要做这个配置一般有两种方式:
- 配置文件中进行配置
- 配置类中进行创建
我们可以创建多个配置类进行分类管理,这样子的话项目结构会清晰很多。
@Configuration注解用在类上,它告诉Spring这是一个配置类。然后我们就可以在这个配置类中使用@Bean的方式来创建各个组件。
注意:最终配置类本身也是容器中的组件!
分层组件注解
为了适配MVC分层模型衍生出来了几个注解,这样可以在不同的分层上指定不同的注解。而且这些分组件也不需要每个都配置到配置类中的@Bean
- @Controller 控制层
- @Service 业务层
- Repository 持久层
- @Component 其它普通组件
这些分层组件只是大家约写的一种写法,实际上你在不同的分层上写上不同的注解效果是一样的。只是说有了这种约定后大家看到项目结构就一目了然了,哪个控制层,哪个是业务层啊...通过类上的分层注解一下子就可以看出来。
注意:分层注解的底层都是@Component,所以它们的功能都是通统一的,只是做出来一个别名方便人为的阅读而已!
@ComponentScan注解
这个注解标注在类上,一般来说标注在入口程序所在的类上。
对于我们的类我们使用了MVC的分层注解,容器可以找到是因为我们通常是把些个分层的类组织到了主程序的子包中,这样子的话Spring默认是会去找这些带注解的类并初始化放到容器中的,如果我们的类不在入口程序性类或其子包下则需要我们使用@ComponentScan来指定让Spring去哪里找(去哪些包及子包下扫描)
比如:我们要求扫描com.xiaoxie包及其子类可以这样子写:
@ComponentScan({'com.xiaoxie'})
注意:一般按约定是把MVC分层的包都放在主程序所在类的子包下!
第三方组件导入容器
如果不是我们自己的类,那肯定不在我们主程序所有包及子包下,我们如果导入进去(把它变为一个组件)让我们使用?
有两个方式:
方式一:使用@Bean在配置类中进行创建注册进容器中
@Bean
public CoreConstants coreConstants() {
return new CoreConstants();
}