文章目录
一、简介
Spring提供了一系列的注解来替代 xml 中的配置,而在实际开发中,建议使用:注解+配置 的形式。
二、IOC注解
(一)常用的注解
常用的注解,区分组件Bean的类型,是根据Bean实现的功能不同来确定在IOC容器中是一个什么组件
注解名称 | 说明 |
---|---|
@Component | 定义Bean组件,添加到IoC容器中,不区分组件类型 |
@Repository | 表示Dao组件(区分组件) |
@Service | 表示Service组件(区分组件) |
@Controller | 表示Action组件(区分组件) |
(二)扫描包
通过在配置文件中扫描包库,看是否存在加载了注解的类,如果类有上面表格常用的容器注解,说明此类是IOC容器的Bean,扫包可以配置多个,但这个地方需要注意,不要扫描太多,一般只扫描需要带有注解的包,因为扫包是要花时间的。具体在xml中扫描的代码示例如下:
<!-- TODO:1.扫描指定的类包,看是否存在以@Component,@Service,@Repository,@Controller开始的类注解,如果有的话,
将其加载到IOC容器中,创建IOC的Bean,此时的Bean的名字ID以默认类名,如果在注解中设置了名字,则以命名为Bean的ID名
扫包可以配置多个,但这个地方需要注意,不要扫描太多,一般只扫描需要带有注解的包,因为扫包是要花时间的。-->
<context:component-scan base-package="aop3.action.impl"/>
<context:component-scan base-package="aop3"/> <!--这行扫所aop3包下面所有的类是否包IOC容器Bean注解,需要花费更多的时间-->
(三)数据装配
注解方式的数据装配是直接使用属性进行注入,不是使用setter方法,所以可以没有setter方法.
- 简单数据的装配: 基本数据类型的装配(简单数据类型),是通过@value()来装配的,@Value()中的值放入的都是字符串
// TODO: 2021/6/29 Bean中属性数据装配
// TODO: 2021/6/29 1.基本数据类型的装配(简单数据类型),是通过@value()来装配的,@Value()中的值放入的都是字符串
@Value("hello java")
private String username;
@Value("20")
private int age;
@Value("6000")
private int salary;
@Value("true")
private boolean flag;
// TODO: 2021/6/29 当一个属性需要装配本地文件的时候
@Value("classpath:aop3/aop3.properties")
private Resource resource;
- 默认属性文件的装配
// TODO: 2021/6/29 2.IOC容器中加载java自带的属性转换后置处理器,这个后置处理器将一个属性文件装配到的Resource属性中,通过解析传递给注
// 解的值,然后再从属性文件中读取解析后值对应的内容。
@Value("${password}")
private String password;
在xml配置文件中,需要配置后置处理器,即在IOC容器中加载后置处理器,这里的后置处理器是Spring自还的,能解析传入的值得到相对应的值,得到的这个值是properties文件中的属性名,在这个后置处理器Bean中,传入属性文件properties文件,从而得到相对应的属性值,得新赋值给属性。具体在xml中加载属性解析后置处理器的代码如下:
<!-- TODO: 第一种方式:基于命名空间 -->
<context:property-placeholder location="classpath:aop3/aop3.properties"/>
<!-- TODO:第二种方式:传统的创建Bean -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:aop3/aop3.properties"/>
</bean>
- 其他Bean的装配
一个Bean中的属性为Bean的时候,可以采取自动装配的方式来进行数据装配,装配的先后顺序为,先类型、后名字,相同类型多个,名字都不同的时候,可以指定名字。
// TODO: 2021/6/29 3.其他自定义Bean的装配
// TODO: 2021/6/29 1.使用@Authwired自动装配,这个地方的装配首先是依据类型(byType)进行自动装配,如果IOC容器中包含有多个相同类型的Bean
// TODO: 2021/6/29 后面就按名字byName(按名字)进行装配
// TODO: 2021/6/29 按指定名字进行装配,其注解为:@Quaiifier("指定的名字")
// @Autowired //自动装配,这里的情形是两个相同类型Bean,两个Bean名不同,且和要装配属性名也不同,在这种情况下名都不为可以使用@Quualifier("指定的Bean名")
// @Qualifier("student2")
@Resource //这也是自动装配,是依据名字byName自动从IOC窗口中找到ID指的名字和属性名一样的Bean
private StudentImpl student;
- 集合的装配
如:数组,List,Set,Map,Properties,Resource。在这个地方需要注意的时,这些类型的数据,属性名和在xml文件中定义的ID一致时,会自动装配数据。也可以指定ID的名字来装配数据,在集合中,装配数据用到的注释为:@Resource()
下面的代码是定义在Bean中的集合等相关属性:
// TODO: 2021/6/29 4.特殊数据的装配,如:数组,List,Set,Map,Properties,Resource
// TODO: 2021/6/29 对于集合类型的值的装配,采取的注解为:
// TODO: 2021/6/29 在这个地方,如果属性名和xml配置中命名空间中的ID名相同的时候,会自动装配数据,
@Resource(name = "as")
private Integer[] array;
@Resource(name = "list2")
private List<StudentImpl> list;
// TODO: 2021/6/29 下面三个数据的装配,是因为属性名和IOC容器中装配数据命名空间<util>中的ID名一样,所以会自动装配数据
@Resource
private Set<StudentImpl> set;
@Resource
private Map<StudentImpl, Class> map;
@Resource
private Properties properties;
下面的代码是在XML文件中,给Bean属性装配数据的代码
<!-- TODO:五种非基本数据类型的数据,采取注解方式的数据装配 -->
<!-- TODO:下面的配置主要是给IOC容器中的Bean,采取以注解的方式装配的属性,在这里也是采取命名空间方式来给注入值 -->
<!-- TODO:数组装配 -->
<util:list id="as">
<value></value>
<value>2</value>
<value>3</value>
</util:list>
<!-- TODO:List装配,一般在类中定义的属性为泛型,指定存储到List集合中的数据类型 -->
<util:list id="list2">
<ref bean="newstudent"/>
<ref bean="student2"/>
<bean class="aop3.action.impl.StudentImpl">
<property name="name" value="c++"/>
<property name="age" value="30"/>
<property name="score" value="99"/>
</bean>
</util:list>
<!-- TODO:Set<>装配,也是依据泛型确定的数据类型进行装配 -->
<util:set id="set">
<!-- TODO:由于是set集合,是无序不可重复的,所以放入两个相同的Bean时,不入存入 -->
<ref bean="student2"/>
<ref bean="student2"/>
<ref bean="student2"/>
<bean class="aop3.action.impl.StudentImpl">
<property name="name" value="c++"/>
<property name="age" value="30"/>
<property name="score" value="99"/>
</bean>
</util:set>
<!-- TODO:Map<>的装配 -->
<util:map id="map">
<!-- TODO:Map中是键值对节点,键和值存储的数据类型两种:基本数据类型和引用数据类型,所以键值对节点有key和value,
key-ref和value-ref之分-->
<entry key-ref="student2" value="StudentImpl.class"/>
<entry key-ref="newstudent" value="StudentImpl.class"/>
</util:map>
<!-- TODO:properties属性数据的装配 -->
<util:properties id="properties">
<prop key="password">123456</prop>
</util:properties>
三、生命周期
一个Bean的生命周期,通过注解@PostConstruct在Bean装配数据后主动调用自定义的init()初始化的方法在Bean销毁前,主动调用自定义的destory()方法。
// TODO: 2021/6/29 一个Bean的生命周期,通过注解@PostConstruct在Bean装配数据后主动调用自定义的init()初始化的方法,
// 在Bean销毁前,主动调用自定义的destory()方法
@PostConstruct //装配数据后执行
public void init() {
System.out.println("数据装配完成后,初始化Bean");
}
@PreDestroy //Bean销毁前执行
public void destory() {
System.out.println("Bean销毁前,调用的方法");
}
四、Bean实例化的时机
Bean的实例化时机,是指IOC容器中的Bean是在IOC容器形成时而形成,还是在从IOC容器中调用getBean()方法才形成。其用到的注解为:@Lazy
@Lazy //此注解决定了此Bean在IOC容器创建的时机,此注解说明是在调用getBean()方法后创建
五、Bean在IOC容器中单例和多例
在IOC容器中,一个Bean是单例还是多例可以通过注解@Scop()来设定,当值为:singleton时,为单例;当值为:prototype时,为多例。具体的代码为:
@Scope("prototype") //此注解为作用域注解,即在IOC中获得的Bean是单例的还是多例的,simple为单例,prototype为多例
六、SpringIOC注解完整示例代码
(一)创建接口及接口的实现类
- 接口
public interface UserAction {
}
- 其他类
import aop3.pos.StringToUserPropertiesEditor;
import org.springframework.stereotype.Component;
/**
* ClassName: StudentImpl;
* User: FWJWORK;
* PackageName: aop3.action.impl;
* Date:2021/6/29;
* Time:18:43;
* Descritpion: <br>
*/
@Component("student2")
public class StudentImpl {
private String name;
private int age;
private int score;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
(二)将实现类定义为IOC容器中的Bean
import aop3.action.UserAction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
// TODO: 2021/6/29 通过注解定义IOC容器Bean的两种方式,第一种是以类名为Bean的ID名,第二种是自定义的名字为Bean的ID名
// TODO: 2021/6/29 同时,一个Bean类,可以区分组件类型,在用注解定义为IOC容器中的一个Bean时,
// 区分组件Bean的定义注解有:@Repository;@Service;@Contorller
@Component //此注解声明是IOC容器中的一个Bean,通过配置文件扫描包可以创建到IOC容器中
//@Component("methonName")
@Lazy //此注解决定了此Bean在IOC容器创建的时机,此注解说明是在调用getBean()方法后创建
@Scope("prototype") //此注解为作用域注解,即在IOC中获得的Bean是单例的还是多例的,simple为单例,prototype为多例
public class UserActionImpl implements UserAction {
// TODO: 2021/6/29 Bean中属性数据装配
// TODO: 2021/6/29 1.基本数据类型的装配(简单数据类型),是通过@value()来装配的,@Value()中的值放入的都是字符串
@Value("hello java")
private String username;
@Value("20")
private int age;
@Value("6000")
private int salary;
@Value("true")
private boolean flag;
// TODO: 2021/6/29 当一个属性需要装配本地文件的时候
@Value("classpath:aop3/aop3.xml")
private Resource resource;
// TODO: 2021/6/29 2.IOC容器中加载java自带的属性转换后置处理器,这个后置处理器将一个属性文件装配到的Resource属性中,通过解析传递给注
// 解的值,然后再从属性文件中读取解析后值对应的内容。
@Value("${password}")
private String password;
// TODO: 2021/6/29 3.其他自定义Bean的装配
// TODO: 2021/6/29 1.使用@Authwired自动装配,这个地方的装配首先是依据类型(byType)进行自动装配,如果IOC容器中包含有多个相同类型的Bean
// TODO: 2021/6/29 后面就按名字byName(按名字)进行装配
// TODO: 2021/6/29 按指定名字进行装配,其注解为:@Quaiifier("指定的名字")
// @Autowired //自动装装,这里的情奖品是有两个同类型,不同名的Bean,且名都不为student
// @Qualifier("student2")
@Resource //这也是自动装配,是依据名字byName自动装配
private StudentImpl student;
// TODO: 2021/6/29 4.特殊数据的装配,如:数组,List,Set,Map,Properties,Resource
// TODO: 2021/6/29 对于集合类型的值的装配,采取的注解为:
// TODO: 2021/6/29 在这个地方,如果属性名和xml配置中命名空间中的ID名相同的时候,会自动装配数据,
@Resource(name = "as")
private Integer[] array;
@Resource(name = "list2")
private List<StudentImpl> list;
// TODO: 2021/6/29 下面三个数据的装配,是因为属性名和IOC容器中装配数据命名空间<util>中的ID名一样,所以会自动装配数据
@Resource
private Set<StudentImpl> set;
@Resource
private Map<StudentImpl, Class> map;
@Resource
private Properties properties;
// TODO: 2021/6/29 一个Bean的生命周期,通过注解@PostConstruct在Bean装配数据后主动调用自定义的init()初始化的方法,
// 在Bean销毁前,主动调用自定义的destory()方法
@PostConstruct //装配数据后执行
public void init() {
System.out.println("数据装配完成后,初始化Bean");
}
@PreDestroy //Bean销毁前执行
public void destory() {
System.out.println("Bean销毁前,调用的方法");
}
}
(三)通过xml文件配置IOC窗口
<?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:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
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 http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!-- TODO:1.扫描指定的类包,看是否存在以@Component,@Service,@Repository,@Controller开始的类注解,如果有的话,
将其加载到IOC容器中,创建IOC的Bean,此时的Bean的名字ID以默认类名,如果在注解中设置了名字,则以命名为Bean的ID名
扫包可以配置多个,但这个地方需要注意,不要扫描太多,一般只扫描需要带有注解的包,因为扫包是要花时间的。-->
<context:component-scan base-package="aop3.action.impl"/>
<context:component-scan base-package="aop3"/> <!--这行扫所aop3包下面所有的类是否包IOC容器Bean注解,需要花费更多的时间-->
<!-- TODO: 第一种方式:基于命名空间 -->
<context:property-placeholder location="classpath:aop3/aop3.properties"/>
<!-- TODO:第二种方式:传统的创建Bean -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:aop3/aop3.properties"/>
</bean>
<!-- TODO:再创建一个StudentImpl类Bean在IOC容器中,一个是用注解@Component创建的,目的是用于自动配置,自动配置都是先按类型,再按名字 -->
<bean id="newstudent" class="aop3.action.impl.StudentImpl">
<property name="name" value="python"/>
<property name="age" value="20"/>
<property name="score" value="100"/>
</bean>
<!-- TODO:五种非基本数据类型的数据,采取注解方式的数据装配 -->
<!-- TODO:下面的配置主要是给IOC容器中的Bean,采取以注解的方式装配的属性,在这里也是采取命名空间方式来给注入值 -->
<!-- TODO:数组装配 -->
<util:list id="as">
<value></value>
<value>2</value>
<value>3</value>
</util:list>
<!-- TODO:List装配,一般在类中定义的属性为泛型,指定存储到List集合中的数据类型 -->
<util:list id="list2">
<ref bean="newstudent"/>
<ref bean="student2"/>
<bean class="aop3.action.impl.StudentImpl">
<property name="name" value="c++"/>
<property name="age" value="30"/>
<property name="score" value="99"/>
</bean>
</util:list>
<!-- TODO:Set<>装配,也是依据泛型确定的数据类型进行装配 -->
<util:set id="set">
<!-- TODO:由于是set集合,是无序不可重复的,所以放入两个相同的Bean时,不入存入 -->
<ref bean="student2"/>
<ref bean="student2"/>
<ref bean="student2"/>
<bean class="aop3.action.impl.StudentImpl">
<property name="name" value="c++"/>
<property name="age" value="30"/>
<property name="score" value="99"/>
</bean>
</util:set>
<!-- TODO:Map<>的装配 -->
<util:map id="map">
<!-- TODO:Map中是键值对节点,键和值存储的数据类型两种:基本数据类型和引用数据类型,所以键值对节点有key和value,
key-ref和value-ref之分-->
<entry key-ref="student2" value="StudentImpl.class"/>
<entry key-ref="newstudent" value="StudentImpl.class"/>
</util:map>
<!-- TODO:properties属性数据的装配 -->
<util:properties id="properties">
<prop key="password">123456</prop>
</util:properties>
</beans>