Spring注解开发
Spring是轻代码重配置的框架,配置比较繁重,会影响开发效率。这个时候可以通过注解开发,注解代替xml配置文件可以简化配置,提高开发效率。
Spring原始注解
注解分为原始注解和新注解,主要是从逻辑上分的,并没有实际的影响。
原始注解出现的比较早,主要用来替代标签配置的。
注解 | 说明 |
---|---|
@Component | 使用在类上,用于实例化Bean,相当于标签 |
@Controller | 使用在web层类上,用于实例化Bean。语义化的@Component |
@Service | 使用在service层类上,用于实例化Bean。语义化的@Component |
@Repository | 使用在dao层类上,用于实例化Bean。语义化的@Component |
@Autowired | 使用在对象引用字段上,用于根据当前字段类型依赖注入 |
@Qualifier | 使用在对象引用字段上,结合@Autowired一起使用,用于根据名称进行依赖注入 |
@Resource | 使用在对象引用字段上,相当于@Autowired+@Qualifier,按照名称进行依赖注入 |
@Value | 使用在普通类型字段上,注入普通属性 |
@Scope | 使用在类上,标准Bean的作用范围 |
@PostConstruct | 使用在方法上,标注该方法是Bean的初始化方法 |
@PreDestory | 使用在方法上,标注该方法时Bean的销毁方法 |
上述注解中比较常用的是除最后两个之外的所有注解。
注意:
使用注解进行开发时,不需要在applicationContext.xml配置各种Bean了,但是需要配置组件扫描。作用是指定哪个包及其子包下的Bean需要进行扫描,以便识别使用了注解配置的类、字段和方法。
<!--注解的组件扫描-->
<context:component-scan base-package="cs.wy"/>
Spring注解开发 - QuicStart
-
在 ApplicationContext.xml中中引入context命名空间和约束文件,并添加组件扫描
-
编写UserDaoImpl类,并使用@Component(或者@Repository)进行标注,告诉Spring容器实例化该类。
//该接口因为不会被配置进xml文档,所以不需要添加注解
public interface UserDao{
public void save();
}
//@Component("userDao") 其中userDao相当于Bean标签的id值
@Repository("userDao") // 作用于dao层类上,用于实例化Bean。语义化的 @Component
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("save running... ...");
}
}
- 使用@Compont 或 @Service 标识UserServiceImpl需要Spring进行实例化
- 使用@Autowired 或者 @Autowired+@Qulifier 或者 @Resource 进行userDao的注入
//@Component("userService")
@Service("userService") // 使用在service层类上,用于实例化Bean。语义化的 @Component
public class UserServiceImpl implements UserService {
/*@Autowired 使用在对象引用字段上,用于根据当前字段类型依赖注入
* @Qualifier("userDao") 使用在对象引用字段上,结合@Autowired一起使用,用于根据名称进行依赖注入
* 其中,value相当于Bean标签property子标签中ref的值
* */
@Resource(name="userDao") // 使用在对象引用字段上,相当于@Autowired+@Qualifier,按照名称进行依赖注入
private UserDao userDao;
@Override
public void save() {
userDao.save();
}
}
用于创建对象的注解:他们的作用都是一样的,如在xml配置文件中,编写一个< bean >标签实现的功能一样的
- Component:当不知道该类属于软件分层的哪一层时,使用该注解,实例化Bean
+ 作用:用于把当前类对象存入Spring容器中
* 属性:value:用于指定bean的id,不写,默认是当前类名,首字母小写 - Controller 使用在web层类上
- Service 使用在Service层上
- Repository 使用在Dao层上
- 上述三个注解作用和属性与 Component 是一模一样的,是Spring框架提供明确的三层使用注解,使三层架构更加清晰
用于注入对象的注解:作用和xml配置文件中的bean标签中写一个property标签作用一样的
- Autowired :
* 作用:自动按照类型注入,按照被标注的成员变量的数据类型在Spring容器中进行匹配,如果找到一样的,就把对应的对象赋值给被标注的成员变量。但如果在Spring容器中存在符合要求的多个bean,这个时候会无法识别使用哪个bean。
* 出现位置:可以是变量上,也可以是方法上
* 细节:使用注解注入时,set方法可以不写 - Qualifier:
* 作用:在按照类中注入的基础上,在按照名称注入,他给类成员注入是不能单独使用,需和@Autowired一起使用,但是在给方法参数注入时可以
* 属性:value:用于指定注入bean的id值 - Resource(name=“Bean的名称”)
* 作用:name为id的值。直接按照Bean的id注入,可以独立使用
* 属性:name:用于指定bean的id值- 以上上个注入都只能注入其他Bean类型的数据,而基本类型和String类型无法使用上述注解实现,另外,集合类型的注入只能通过xml配置来实现
- Value(“value”):
* 作用:用于注入基本类型和String类型的数据
* 属性:value:用于指定数据的值,他可以使用Spring中的SpEL(也就是Spring的el表达式)
* SpEL的写法:${表达式}
* KaTeX parse error: Expected 'EOF', got '#' at position 20: …来取外部文件的值 * #̲{}是用来取Bean的属性值,…{jdbc.driver}") 在Spring配置文件中导入Properties文件后,可以通过key(jdbc.driver)获得value值
用于改变作用范围的注解:作用和bean标签中使用scope属性功能一样
- Scope:
* 作用:指定bean的作用范围
* 属性:value:指定范围的取值,value的常用取值有prototype和singleton
和生命周期相关注解
- @PostConstruct 被标注的成员方法,将成为对象的初始化方法
- @PreDestroy 被标注的成员方法,将成为对象的销毁方法
Spring常用新注解
使用原始注解不能替代Spring配置文件中全部内容,新注解可以替代如下配置:
1)非自定义的Bean的配置:例如DataSource
2)加载Properties文件的配置:<context:property-placeholder path=“classpath:xxx”/>
3)Spring注解组件扫描器配置:<context:component-scan base-package=""/>
4)引入其他xml配置文件:
针对以上4中情况,Spring提供新注解如下:Spring新注解的替代思想:使用一个类(核心配置类)替代xml核心配置文件,在类上使用注解代替原来xml文件中的标签。
注解 | 说明 |
---|---|
@Configuration | 标注在特殊的指定类上,被标注的类就是Spring核心配置类 |
@ComponentScan(“包名”) | 标注在特殊的指定类上,指定组件扫描范围,效果等同于<context:component-scan base-package=“包名”/> |
@Bean(“value”) | 标注在特殊指定类中的方法上,用于”标注“非自定的Bean,标注方式 有些特殊:Spring会将被标注方法的返回值存储在Spring容器中。效果等同于<bean id=“dataSource” class=“com.mchange.v2.c3p0.ComboPooledDataSource”"> |
@PropertySource | 标注在特殊指定的类上或者其@import类上,将指定的properties文件加载进Spring容器。写法为@PropertySource(“classpath:xxx.properties”)。效果等同于<context:property-placeholder path=“calsspath:xxx”/> |
@import | 标注在特殊指定的类上,作用:将拆分出去的配置类引入到核心配置类内,写法为:@import({xxx.class, yyy.class})。 效果上等同于 |
全注解代码如下:
1)创建Spring核心配置类SpringConfiguration.java,并添加对应注解
//被该注释标注后表示该类为Spring核心配置类
@Configuration
//指定组件扫描范围,相当于<context:component-scan base-package="包名"/>
@ComponentScan("cs.wy")
//引入拆分出去的配置类,相当于<import resource="xxx.xml"/>
@Import(DataSourceConfiguration.class)
public class SpringConfiguration{
}
2)新建jdbc.properties文件,将数据源连接基本参数配置其中:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/maven
user=root
password=135246
3)创建Spring核心配置类拆分出去的数据源配置类DataSourceConfiguration.java,并添加相应注解
//将Properties文件加载进Spring容器,
//相当于<context:property-placeholder path="calsspath:xxx"/>
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfiguration{
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${user}")
private String username;
@Value("${password}")
private String password;
@Bean("dataSource")
public DataSource getDataSource() throws Exception {
//创建数据源
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//为数据源设置连接基本参数
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
//返回创建好的数据源
return dataSource;
}
}
常用新注解详解
Configuration
- 作用:指定当前类是一个配置类
- 细节:
- 当配置类作为AnnotationConfigApplicationContext对象创建参数时,该注解可以不写
- @Configuration这个注解什么时候必须写,什么时候可以省略
- 如果在AnnotationConfigApplicationContext(xxx.class)中指定了该配置文件的字节码对象,就可以省略不写
- 没有指定,就要在主配置文件中要写,扫描子配置类,那么子配置类也必须要写
- 也可以通过@Import(JdbcConfig.class)来指定子配置类,如果使用也可以省略@Configuration
ComponentScan
- 作用:用于通过注解指定Spring在创建容器的时候要扫描的包
- 属性:value:它和basePackages的作用一样的效果等同于<context:component-scan base-package=“包名”/> |
Bean
- 作用:用于把当前方法的返回值作为bean对象存入Spring的容器中
- 属性:name用于指定bean的id值,当不写时,默认当前方法的名称
- 细节:当使用注解配置的时候,如果方法有参数,Spring框架会去容器查找有没有可用的bean对象,查询方式和Autowired注解的作用一样的
- 先按照类型去找,没有就报错
- 如果有且只有一个,就自动注入
- 如果有多个,会按照形参名称去匹配,匹配成功则自动注入
- 匹配不是还是会报错
- 可用使用Qualifier去指定要注入的bean的id
Import
- 作用:导入其他的配置类
- 属性:value:指定其他配置类的字节码,使用这个注解,有Import的注解类就是父类,导入的都是子类
PropertySource
- 作用:用于指定properties文件的位置
- 属性:value:指定文件的路径和名称。
* 关键字:classpath,表示类路径下
* 在Spring中如果要读取配置文件,一般都要加classpath:关键字
* classpath:就是在classpath下面去找
* classpath*:就在classpath 下面所有的文件去找,包含子目录下