Spring注解开发

作者 : admin 本文共12701个字,预计阅读时间需要32分钟 发布时间: 2024-06-10 共2人阅读

从前面的内容我们可以发现,Spring开发中有许多的配置,非常的费时费力,影响开发效率。

Spring本身就是一个轻代码而重配置的框架,配置比较繁重,影响开发效率,所以就在Spring中加入了注解,使用注解代替原来的xml配置文件,这样就可以简化配置,提升开发效率。

一、Bean 基本注解开发

注解方式慢慢成为xml配置的替代方案

基本Bean注解,主要是使用注解的方式替代原有xml的 标签及其标签属性的配置

<bean id="" name="" class="" scope="" lazy-init="" init-method="" destroy-method="" 
      
abstract="" autowire="" factory-bean="" factory-method=""></bean>

使用@Component 注解替代标签

XML配置注解描述
bean id=“” class=“@Component 被该注解标识的类,会在指定扫描范围内被Spring加载并实例化

1.1 @Component Bean的配置

value属性指定当前Bean实例的beanName,也可以省略不写,不写的情况下为当前类名首字母小写

//获取方式:applicationContext.getBean("userDao");
@Component("userDao")
public class UserDaoImpl implements UserDao {
}

//获取方式:applicationContext.getBean("userDaoImpl");
@Component
public class UserDaoImpl implements UserDao {
}

这样配置还不算完,Spring还不知道我们要扫描这个注解,所以还需要配置扫描的范围

<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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 告知Spring框架去com.zhangjngqi包及其子包下去扫描使用了注解的类 -->
    <context:component-scan base-package="com.zhangjingqi"/>
</beans>    

此时就能获取到注解创建的UserServiceImpl对象

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Object userService = applicationContext.getBean("userDaoImpl");
System.out.println(userService);

1.2 其他注解配置Bean

@Component就单纯一个value属性,那么xml配置 时那些属性怎么进行配置呢?

Spring 是通过注解方式去配置的之前 标签中的那些属性,例如:@Scope

<bean id="" name="" class="" scope="" lazy-init="" init-method="" destroy-method="" 
      
abstract="" autowire="" factory-bean="" factory-method=""></bean>
xml配置注解描述
bean scope=“”@Scope在类上或使用了@Bean标注的方法上,标注Bean的作用范围,取值为singleton或prototype
bean lazy-init=“”@Lazy在类上或使用了@Bean标注的方法上,标注Bean是否延迟加载,取值为true和false
bean init-method=“”@PostConstruct在方法上使用,标注Bean的实例化后执行的方法
bean destroy-method=“”@PreDestroy在方法上使用,标注Bean的销毁前执行方法
@Component("userDao")
@Scope("singleton")
@Lazy(true)
public class UserDaoImpl implements UserDao{
   @PostConstruct
   public void init(){}
    
   @PreDestroy
   public void destroy(){}
}

1.3 @Component 衍生注解

注解说明
@Controller标注在控制器
@Service标注在业务类上
@Repository标注在数据访问类上(由于与Mybatis整合,用的少)

不属于上面三层的,大多数使用@Component就可以

@Repository("userDao")
public class UserDaoImpl implements UserDao{}

@Service("userService")
public class UserServiceImpl implements UserService{}

@Controller("userService")
public class UserController {}

二、Bean依赖注入注解开发

Bean依赖注入的注解,主要是使用注解的方式替代xml的 标签完成属性的注入操作

之前的注入方式

<bean id="" class="">
   <property name="" value=""/>
   <property name="" ref=""/>
</bean>

如今注解注入方式

属性注入注解描述
@Value使用在字段或方法上,用于注入普通数据
@Autowired使用在字段或方法上,用于根据类型(byType)注入引用数据
@Qualifier使用在字段或方法上,结合@Autowired,根据名称注入
@Resource使用在字段或方法上,根据类型或名称进行注入

说明
@Resource注解是Java EE规范提供的,它在JDK中的javax.annotation.Resource包中定义。
在Spring中,可以使用@Resource注解来注入Bean,但它也支持其他注解,如@Autowired和@Inject。这些注解提供了相同的功能,但有些微小的差异。
@Autowired注解是Spring提供的,而@Inject注解是JSR-330规范中定义的。

2.1 @Value

  • 直接注入普通属性
@Value("haohao")
private String username;

@Value("haohao")
public void setUsername(String username){
    System.out.println(username);
}

基本上没这么做的,主要看第二点,注入注入properties文件中的属性

  • 注入properties文件中的属性
@Value("${jdbc.username}")
private String username;

@Value("${jdbc.username}")
public void setUsername(String username){
    System.out.println(username);
}

加载properties文件

<context:property-placeholder location="classpath:jdbc.properties"/>

2.2 @Autowired

//使用在属性上直接注入
@Autowired
private UserDao userDao;

//使用在方法上直接注入
@Autowired
public void setUserDao(UserDao userDao){
      System.out.println(userDao);
}

当容器中同一类型的Bean实例有多个时,会尝试自动根据名字进行匹配(如果名字匹配不成就会报错)

//匹配当前Bean
@Repository("userDao")
public class UserDaoImpl implements UserDao{}

@Repository("userDao2")
public class UserDaoImpl2 implements UserDao{}

下面的这段话也能注入UserDao,但是只不过仅仅在此方法中使用

@Autowired
public void xxx(UserDao userDao){
    System.out.println(userDao);
}

下面这段自动注入的含义是,在Spring容器中找UserDao类型的对象,然后放入到userDaoList集合当中

@Autowired
public void yyy(List<UserDao> userDaoList){
    System.out.println(userDaoList);
}

2.3 @Qualifier

@Qualifier配合@Autowired可以完成根据名称注入Bean实例,使用@Qualifier指定名称

@Autowired
@Qualifier("userDao2")
  private UserDao userDao;

@Autowired
@Qualifier("userDao2")
public void setUserDao(UserDao userDao){
  System.out.println(userDao);
}

别的地方@Qualifier可以单独使用

2.4 @Resource

@Resource注解存在与 javax.annotation 包中,Spring对其进行了解析

说明
@Resource注解是Java EE规范提供的,它在JDK中的javax.annotation.Resource包中定义。
在Spring中,可以使用@Resource注解来注入Bean,但它也支持其他注解,如@Autowired和@Inject。
这些注解提供了相同的功能,但有些微小的差异。
@Autowired注解是Spring提供的,而@Inject注解是JSR-330规范中定义的。

@Resource注解既可以根据类型注入,也可以根据名称注入,无参就是根据类型注入,有参数就是根据名称注入

@Resource
private UserDao userDao;

@Resource(name = "userDao2")
public void setUserDao(UserDao userDao){
    System.out.println(userDao);
}

@Resource注解会首先根据name属性指定的名称去查找对应的Bean进行注入,如果找到了,则使用名称匹配的方式注入;

如果没有指定name属性或者找不到匹配的Bean,则根据类型进行注入。

如果有多个同类型的Bean,也会使用名称匹配的方式来确定要注入哪个Bean。需要注意的是,如果有多个同类型且同名称的Bean,那么@Resource注解会抛出NoUniqueBeanDefinitionException异常。

@Resource与@Autowired区别:
来源不同:@Resource是Java EE规范定义的注解,而@Autowired是Spring框架定义的注解。
注入方式不同:@Resource默认按照Bean的名称进行注入,如果找不到与名称相匹配的Bean,则按照类型进行注入。而@Autowired默认按照类型进行注入,如果出现多个相同类型的Bean,则再按照名称进行匹配。
属性名称不同:@Autowired没有name属性,而@Resource有name属性,可以指定要注入Bean的名称。
是否支持JSR-330:@Autowired支持JSR-330的@Inject注解,而@Resource不支持。

三、非自定义注解开发

@Bean注解必须被扫描到才可以完成下面的操作

@Bean所在的类必须加入到容器,可以加一个@Component注解,也可以添加@Configuration注解,一般是@Configuration注解

3.1 无参非自定义注解开发

非自定义Bean要通过工厂的方式进行实例化,使用@Bean标注方法即可

@Bean的属性为beanName,如不指定为当前工厂方法名称

测试一下:

@Component
public class DataSourceTest {
    //将方法返回值Bean实例以@Bean注解指定的名称存储到Spring容器中
    @Bean("dataSource222")
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
}

很完美:

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Object userService = applicationContext.getBean("dataSource222");
System.out.println(userService);

如果不给@Bean添加参数呢,默认是什么名字?

​ 默认是方法名,如果是dataSource(),那Bean就叫dataSource,如果是DataSource(),那Bean就叫DataSource

@Bean
public DataSource dataSource(){
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
    dataSource.setUsername("root");
    dataSource.setPassword("root");
    return dataSource;
}

3.2 有参非自定义注解开发

注意! 下面方法所在的类是@Component注解修饰的,如果是@Configuration注解修饰的,部分方法会报错

如果@Bean工厂方法需要参数的话,则有如下几种注入方式

1.使用@Autowired 根据类型自动进行Bean的匹配,@Autowired可以省略

不省略的形式:

@Bean
public DataSource beanTest01(@Autowired UserDao userDao,@Autowired UserService userService){
    System.out.println(userDao);
    System.out.println(userService);
    DruidDataSource dataSource = new DruidDataSource();
    return dataSource;
}

省略的形式:

@Bean
public DataSource beanTest01(UserDao userDao,UserService userService){
    System.out.println(userDao);
    System.out.println(userService);
    DruidDataSource dataSource = new DruidDataSource();
    return dataSource;
}

2.使用@Qualifier 根据名称进行Bean的匹配

以前是@Autowired+@Qualifier注解,在这个地方仅仅使用@Qualifier也可以

@Bean
public DataSource beanTest01(@Qualifier("userDaoImpl") UserDao userDao, UserService userService){
    System.out.println(userDao);
    System.out.println(userService);
    DruidDataSource dataSource = new DruidDataSource();
    return dataSource;
}

3.使用@Value 根据名称进行普通数据类型匹配

从properties文件中读取jdbc.driver开头的Key对应的Value

@Bean("dataSource")
public DataSource dataSource(@Value("${jdbc.driver}") String driverClassName){
    
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName(driverClassName);
}    

四、Spring配置类的开发

@Component等注解替代了bean标签,但是像 import、context:componentScan 等非bean 标签怎样去使用注解替代呢?

<!-- 加载properties文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>

<!-- 组件扫描 -->
<context:component-scan base-package="com.itheima"/>

<!-- 引入其他xml文件 -->
<import resource="classpath:beans.xml"/>

4.1 @Configuration注解

@Configuration注解标识的类为配置类,替代原有xml配置文件,该注解第一个作用是标识该类是一个配置类,第二个作用是具备@Component作用

//标注当前类是一个配置类(替代配置文件的)
//底层也封装了@Component注解
@Configuration
public class SpringConfig {
}

4.2 @ComponentScan 组件扫描配置

@ComponentScan 组件扫描配置,替代原有xml文件中的

@Configuration
@ComponentScan({"com.zhangjingqi.service","com.zhangjingqi.dao"})
public class SpringConfig {}
  • 指定一个或多个包名:扫描指定包及其子包下使用注解的类
  • 不配置包名:扫描当前@componentScan注解配置类所在包及其子包下的类

4.3 @PropertySource

注解用于加载外部properties资源配置,替代原有xml中的 配置

@Configuration
@ComponentScan
@PropertySource({"classpath:jdbc.properties","classpath:xxx.properties"})
public class SpringConfig {}

4.4 @Import注解

相当于import resource=“”配置

首先说明DataSourceTest类上没有任何注解

@Configuration
@ComponentScan("com.zhangjingqi")//一定要扫描到DataSourceTest所在的包
@Import(DataSourceTest.class)
public class SpringConfig {
}

此时就将DataSourceTest注入容器了,并且DataSourceTest的@Bean所修饰 的Bean也注入容器了

DataSourceTest类相当于一个小的配置类(类似分部)

SpringConfig类在这里相当于一个大的配置类(类似总部)

public class DataSourceTest {
    //将方法返回值Bean实例以@Bean注解指定的名称存储到Spring容器中
    @Bean("dataSource")
    public DataSource dataSource(@Value("${jdbc.driver}") String driverClassName, UserDaoImpl userDao){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }


    @Bean
    public DataSource beanTest01(@Qualifier("userDaoImpl") UserDao userDao, UserService userService){
        System.out.println(userDao);
        System.out.println(userService);
        DruidDataSource dataSource = new DruidDataSource();
        return dataSource;
    }
}

4.5 加载配置类

//        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//        注解方式加载Spring核心配置
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
Object springConfig = applicationContext.getBean("springConfig");
Object userDao = applicationContext.getBean("userDaoImpl");
System.out.println(springConfig);
System.out.println(userDao);

五、Spring配置其他注解

5.1 @Primary

@Primary注解用于标注相同类型的Bean优先被使用权

@Primary 是Spring3.0引入的,与@Component和@Bean一起使用,标注该Bean的优先级更高,则在通过类型获取Bean或通过@Autowired根据类型进行注入时,会选用优先级更高的

@Repository("userDao")
public class UserDaoImpl implements UserDao{}

@Repository("userDao2")
@Primary
public class UserDaoImpl2 implements UserDao{}
// 如果通过类型UserDao.class获取对象时,第二个Bean new UserDaoImpl2 会优先获取
@Bean
public UserDao userDao01(){
    return new UserDaoImpl();  
}

@Bean
@Primary
public UserDao userDao02(){
    return new UserDaoImpl2();
}

5.2 @Profile

@Profile 注解的作用同于xml配置时学习profile属性,是进行环境切换使用的

<beans profile="test">

注解 @Profile 标注在类或方法上,标注当前产生的Bean从属于哪个环境,只有激活了当前环境,被标注的Bean才能被注册到Spring容器里
不指定环境的Bean,任何环境下都能注册到Spring容器里

@Repository("userDao")
@Profile("test")
public class UserDaoImpl implements UserDao{}

@Repository("userDao2")
public class UserDaoImpl2 implements UserDao{}

怎么激活环境?

1.使用命令行动态参数,虚拟机参数位置加载

 -Dspring.profiles.active=test

2.使用代码的方式设置环境变量

System.setProperty("spring.profiles.active","test");

六、Spring注解与xml对比

​ @Component在类上标注完,Spring扫描到后,会被实例化成对象,再存储到Spring容器之中,现在研究一下为什么能创建对象

​ 依然是下面这张图
Spring注解开发插图
使用@Component等注解配置完毕后,要配置组件扫描才能使注解生效
Spring注解开发插图(1)

七、注解方式整合MyBatis

7.1 注解方式整合

之前的配置方式

<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
   <property name="url" value="jdbc:mysql://localhost:3306/mybatis"></property>
   <property name="username" value="root"></property>
   <property name="password" value="root"></property>
</bean>

<!--配置SqlSessionFactoryBean-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
   <property name="dataSource" ref="dataSource"></property>
</bean>

<!--配置Mapper包扫描-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.itheima.dao"></property>
</bean>

如今的配置方式:

@Configuration
@ComponentScan("com.zhangjingqi")
@MapperScan("com.zhangjingqi.mapper")
public class SpringConfig {
    @Bean
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
        dataSource.setUsername("root");
        dataSource.setPassword("root");

        return dataSource;
    }
    
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
       SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
       sqlSessionFactoryBean.setDataSource(dataSource);
       return sqlSessionFactoryBean;
     }
  
}    

扫描

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);

7.2 原理

,Spring整合MyBatis的原理,关键在于@MapperScan,@MapperScan不是Spring提供的注解,是MyBatis为了整合Spring,在整合包org.mybatis.spring.annotation中提供的注解

@MapperScan注解内部有一个注解是@Import,然后导入了一个类MapperScannerRegister
Spring注解开发插图(2)
点进MapperScannerRegister类,发现此类实现一个接口ImportBeanDefinitionRegister,一看就是一个BeanDefinition注册器
Spring注解开发插图(3)
ImportBeanDefinitionRegister接口中有一个方法registerBeanDefinitions
Spring注解开发插图(4)
再回到MapperScannerRegister类中,搜一下registerBeanDefinitions方法

然后发现类MapperScannerRegister中对registerBeanDefinitions方法重载了
Spring注解开发插图(5)
看一下重载的registerBeanDefinitions方法,然后发现此方法中在构建BeanDefinition时传入了MapperScannerConfig类

<!--配置Mapper包扫描-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.itheima.dao"></property>
</bean>

这个类就是在xml配置文件中配置的类org.mybatis.spring.mapper.MapperScannerConfigurer

Spring注解开发插图(6)
MapperScannerConfigurer实现了BeanDefinitionRegisterProcessor接口,这个接口我们见到了很多次了
Spring注解开发插图(7)
不管是注解方式还是xml方式,最终还会回到MapperScannerConfigurer

本站无任何商业行为
个人在线分享 » Spring注解开发
E-->