实际开发中经常需要使用基于Spring的完全注解开发,在这里对常用注解与基本开发流程做一个简单的总结归纳
1. 定义配置类
@Configuration // 表示这是一个配置类
@ComponentScan(basePackages = {"com.alibaba.bean", "com.alibaba.bean2"})
// 表示开启组件扫描
// 这个注解中的属性填的是我们要扫描的包的名称,以basePackages做参数可以传入多个包名
// 注意这个组件扫描不是一定要开启,如果采用另一种方式定义Bean就不需要,见下文
2. 定义Bean对象
方式一:@ComponentScan + 类名上添加四大注解
Spring提供了四中注解供我们创建Bean对象,这四种注解功能是完全一样的,只是为了便于我们更好地区分每个Bean具体的作用。在进行组件扫描的时候,我们也可以根据注解的类型来区分什么类需要创建并添加到当前容器中,什么不需要(使用filter实现)。
@Component @Service @Controller @Repository
我们可以在注解后面添加一个属性,这个属性就是该类的Bean对象在容器中的id,如上图中类Sneaker所对应的Bean在容器中的id为”snk”,在调用的时候可以直接通过getBean(“snk”)来访问到这个Bean对象。
@Scope
这个注解用于指定作用域,默认情况下是单实例,如果像图中这样指定为prototype,则该Bean将是多实例。补充一个知识点:多实例是懒加载,即调用一个才创建一个,而单实例默认是在容器初始化完成时就已经创建好并加载到容器中了,如果我们在单实例下也想使用懒加载,可以使用@Lazy注解
方式二:@Bean + 在配置类中写工厂方法
可以看到此时我们并没有开启组件扫描,而是在加了@Configuration的配置类中写一个返回我们所需要的对象的工厂方法,并加上注解@Bean,在这个注解中,我们可以填入value(也就是存在于容器中的id),初始方法与销毁方法,整个格式与配置文件的方式十分相像。在这种模式下,我们也能直接加上注解@Scope来指定作用域
注意:上述两个方法是可以同时使用的,不冲突。也就是说,我们可以显式在配置类中指定我们要创建的Bean,同时可以开启组件扫描,对添加了指定注解的类也创建对应的Bean并加入到容器中。
3. 设置Bean对象需要注入的属性
注入基本属性:
@Value 我们可以直接使用这一注解为基本数据类型属性如int或者是String注入值。注意,即便是装入int类型,参数也只能使用字符串的形式。
注入自定义类属性(自动装配):
@Autowired 按照类型自动在容器中找到类型匹配的对象进行装配;如果相同类型的对象有多个,则按照属性名称进行装配,即找到容器中id与属性名相同的对象进行装配;如果没有该类型的对象,我们可以在这个注解后面加一个参数值required = false,加了这个参数值后会自动为该属性注入一个null值,不加该参数则会报错。@Autowired不仅可以标注在属性上,还可以标注在构造器上以及set方法上,这些位置都可以完成自动注入
@Qualifier(“id”) 显式指定id进行装配。根据属性类型,找到容器中id值为传入参数的Bean对象,将该对象赋给该属性。常常用于容器中同一类型的对象有多个的时候,显式指定将其中的哪一个作为值进行注入。注意这个注解需要与上述@Autowired一起用
@Primary 在我们没有显式指定Qualifier的时候,可以在一个类上加入该注解,则当需要注入该类型的属性时,我们指定的这个对象会被注入到属性中。
@Resourse 该注解来自javax.annotation依赖包下,同样可以实现自动装配,但他不能搭配我们Primary这种注解使用,灵活性稍差,因此实际开发建议使用@Autowired
为对象注入容器的属性(如ApplicationContext),可以通过使类implements相应的Aware接口来实现,这一步将会发生在populateBean(为Bean填充属性)之后,详情见《Spring深度学习笔记》
4. 自定义BeanPostProcessor
我们可以自定义一个类,用这个类实现BeanPostProcessor接口,同时重写里面对应的postProcessBeforeInitialization 以及 postProcessAfterInitialization方法,就可以在对象调用init-method前后执行对应的代码逻辑。
使用方法:我们在这个类上同样打上了一个@Component注解,这意味着我们会把这个类作为一个普通的Bean对象创建并添加到容器中。因此我们如果想要使用自定义的BeanPostProcessor,记得需要打上四大注解,并开启组件扫描(用方法二创建该类并添加到容器中也能实现对应的逻辑,但编译器会有警告)。
指定顺序:在有多个BeanPostProcessor时,我们可以通过实现ordered接口,重写getOrder方法实现顺序指定,return的数字越小执行优先级越高
5. 在main方法中执行
在这里我们new的对象是AnnotationConfigApplicationContext,传入的参数是我们的配置类,至此我们完成了容器的创建(引用类型可以写成ApplicationContext,但这种引用类型有一些方法会没有,比如close,使用起来可能没有AnnotationConfigApplicationContext方便)。
现在我们可以直接通过getBean方法拿到我们需要的对象,获取对象的方法有根据id、根据类型两种方式。
如果我们没有声明scope,本例中sout出来的结果是true,表示我们两次拿到的是同样的对象;如果我们显式声明了scope为prototype,则输出的结果为false。
关于Spring IOC注解开发最基本的使用先总结到这,其他内容在日后的使用中不断总结更新。