Spring 注解编程

注解基本概念

什么是注解编程

注解编程就是指在或者方法上加入特定的注解(即@XXX),以完成特定的功能实现,例如

1
2
@Component
public class XXX{}

为什么使用注解编程

  • 注解开发更加方便,代码简洁,提高开发速度
  • 注解编程是Spring开发的趋势,Spring2.x引入注解编程,Spring3.x完善注解,SpringBoot开始普及和推广注解编程

注解的作用

  • 代替XML文件这种配置形式,简化配置
    例如使用@Component注解可以代替XML文件中的<bean>标签

  • 代替接口实现调用双方的契约性
    例如之前为了完成面向切面编程,需要一个类实现MethodInterceptor接口,重写invoke方法,有了注解,可以直接在一个类中使用@Pointcut注解表示切入位置,再使用@Before@After@Around等注解完成实际的额外功能的实现

Spring基础注解

对象创建相关注解

首先需要在配置文件中applicationContext.xml开启注解扫描,设置注解扫描的包和子包,如

1
<context:component-scan base-package="cool.yzt"/>

@Component 注解

@Component注解的主要作用就是替换配置文件中的<bean>标签,@Component注解提供了默认的对象ID,即类名的首字母小写,例如

1
2
3
4
@Component
public class User {

}

相当于

1
<bean id="userDAO" class="cool.yzt.dao.userDAO"/>

细节

  • @Component注解也可以显式的指定工厂创建对象时的ID,如@Component("u)
  • Spring配置文件中的设置可以覆盖注解配置的内容

衍生注解

  • @Repository 一般用于DAO层的类
  • @Service 一般用于Service层的类
  • @Controller 一般用于Controller层的类
    这些注解的本质就是@Component,只是为了更准确的表达一个类的作用,作了语义化的区分

@Scope 注解

@Scope注解的作用是控制对象创建的次数,默认值为@Scope("singleton")即单例的,例如controller、service、DAO类一般都是单例的,如果是@Scope("prototype")则每一次从工厂中获取对象时,都会返回一个新的对象

@Lazy 注解

@Lazy注解的作用是延迟创建单例对象,即真正获取或使用这个类的对象时才会完成这个对象的创建

生命周期方法相关注解

注意以下两个注解是加在方法之上的,而且这两个注解并不是Spring提供,而是由JSR250(JavaEE规范)提供的

  • 初始化方法,使用@PostConstruct
  • 销毁方法,使用@PreDestroy(Spring工厂关闭之前执行)

依赖注入相关注解

自定义类型的注入

  1. @Autowired(推荐)
    @Autowired注解是基于类型进行注入的,所注入的对象的类型必须与目标成员变量的类型相同或是其子类或实现类,例如在Controller类中如入Service类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Service
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.print("UserServceImpl.save");
}
}

@Controller
public class UserController() {
@Autowired
private UserService userService;

public void save() {
userService.save();
}
}

@Autowired可以放置在set方法之上也可以放置在成员变量之上,Spring会通过反射直接对成员变量进行注入

  1. @Qualifier
    @Qualifier@Autowired一起使用可以实现基于名字(即创建类时设置的类的ID值)进行注入,一般用于要注入的类型有多个不同的子类或实现类,需要指定具体注入哪一个类

  2. @Resource
    @Resouce注解由JSR250提供,也是基于名字注入(@Resource(name="userDAOImpl")),需要注意的是,如果名字没有配对成功,会继续按照类型尝试再次注入

  3. @Inject
    @Inject注解由JSR330提供,其作用与@Autowired完全一致,同样是基于类型注入,一般用于框架底层的实现

JDK类型的注入

  1. @Value
    进行JDK类型的注入首先需要在xxx.properties文件中设置需要注入的值,例如
1
2
name = yzt
id = 10

然后需要告知Spring工厂读取该文件,可以使用applicationContext.xml配置文件或者@PropertySource注解,如果是前者,需要在xml中添加标签写明properties文件的位置

1
<context:property-placeholder location=""/>

最后只需在需要注入值的成员变量上使用@Vlaue("${key}")即可,key就是文件中等号前的字符串

注意,@Value注解不可以应用在静态成员变量之上

  1. @PropertySource
    @PropertySouce注解可以代替<context:property-placeholder标签来指定xxx.properties文件的位置,例如
1
2
3
4
5
6
7
8
9
@Repository()
@PropertySource("classpath:user.properties")
public class UserDAO {
@Value("${name}")
String userName;

@Value("${id}")
Integer userId;
}

Spring高级注解

配置Bean

Spring在3.x版本提供了@Configuration注解以替换掉xml配置文件,该注解加在一个类上,如

1
2
3
4
@Configuration
public class AppConfig {

}

之前获取通过配置文件配置的Spring工厂的实现类为ClassPathXmlApplicationContext,即

1
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

如果使用配置类,则获取工厂的方式为

1
2
3
4
5
// 指定配置类的类型
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

// 指定配置类的包名
ApplicationContext ctx = new AnnotationConfigApplicationContext("cool.yzt.config")

实际上,@Configuration注解的本质也是@Component的衍生注解

@Bean注解

基本使用

@Bean注解在配置Bean中使用,加在方法之上,可以代替xml配置文件的<bean>标签,例如,替换xml配置文件中的

1
<bean id="user" class="cool.yzt.domain.User"/>

可以替换为

1
2
3
4
5
6
7
@Configuration
public class AppConfig {
@Bean
public User user() {
return new User();
}
}

其中,把实际创建对象的代码写在由@Bean注解修饰的方法之中,该方法的返回值类型为创建的对象的类型,方法名即工厂中该对象的ID值

注意

  • @Bean注解既可以用于创建简单对象(通过new可以直接创建的对象),如UserServiceUserDAO等,也可以用于创建复杂对象(不可以直接new),如MyBatis框架中用到的ConnectionSqlSessionFactory等,把创建对象的代码书写于该方法中即可
  • 自定义对象ID值:@Bean("ID")
  • 控制对象创建次数:同样可以使用@Scope注解

@Bean注解的注入

  1. 自定义类型
1
2
3
4
5
6
7
8
9
10
11
@Bean
public UserDAO userDAO() {
return new UserDAOImpl();
}

@Bean
public UserService userService(UserDAO userDAO) {
UserService userService = new UerServiceImpl();
userService.setUserDAO(userDao());
return userService;
}
  1. JDK类型
    @Bean创建的对象中,依然可以使用@PropertySource+@Value("${key}")的方式注入JDK类型,例如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Configuration
@PorpertySource("classpath:/init.properties)
public class AppConfig {
@Value("${id}")
private Integer id;

@Value("${name}")
private String name;

@Bean
public User user() {
User user = new User();
user.setId(id);
user.setName(name);
return user;
}
}

@ComponentScan 注解

@ComponentScan注解同样与@Configuration配合使用,用于代替xml配置文件中的<context:component-scan base-package="cool.yzt"/>标签

1
2
3
4
5
@Configuration
@ComponentScan(basePackages = "cool.yzt")
public class AppConfig2 {

}

Spring工厂创建对象的多种配置方式

多种配置方式的应用场景

  • xml配置文件:如今纯注解开发是主流,基本不再使用配置文件,老项目中可能遗留
  • @Import:一般用于Spring框架底层,或者用于多配置Bean的整合
  • @Component及其衍生注解、@Autowired:一般用于程序员自己开发的类上
  • @Bean+@Configuration:一般用于框架提供的类型、别的程序员开发的类型(即没有源码的类)上,例如 SqlSessionFactoryBeanMapperScannerConfigure

注意:不同的配置方式是有优先级的,@Component及其衍生注解 < @Bean < 配置文件bean标签,注意优先级高的配置会覆盖优先级低的配置(id相同时)

整合多个配置信息

多个配置Bean的整合

拆分多个配置Bean的开发,是一种模块化的开发形式,体现了面向对象各司其职的设计思想。当存在多个配置Bean时,可以通过以下方式整合汇总。

  1. 创建工厂时,基于basePackages进行整合
1
ApplicationContext ctx = new AnnotationConfigApplicationContext("cool.yzt.config");
  1. 创建工厂时,指定多个配置Bean的Class对象
1
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig1.class, AppConfig2.class);
  1. 使用@Import注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Configuration
@Import(AppConfig2.class)
public class AppConfig1 {
@Bean
public User user() {
return new User();
}
}


@Configuration
public class AppConfg2 {
@Bean
public Product product() {
return new Product();
}
}

配置Bean与@Component相关注解的整合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Repository
public class UserDAOImpl implements UserDAO {

}

@Configuration
@ComponentScan("cool.yzt")
public class AppConfig {
@Autowired
private UserDAO userDAO;

@Bean
public UserService userService() {
UserServiceImpl userService = new UserService();
userService.setUserDAO(userDAO);
return userService;
}
}

ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

参考

孙哥说Spring5


本博客所有文章除特别声明外,均采用 知识共享署名-相同方式共享 4.0 国际许可协议 ,转载请注明出处!