【Spring—注解开发】


一、纯注解开发

Spring3.0开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道。即将配置文件applicationContext.xml删除掉,使用类来替换。

1.1 实现步骤

BookDao 、 BookDaoImpl 、 BookService 、 BookServiceImpl 类如下:

public interface BookDao {
    public void save();
}
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ..." );
    }
}
public interface BookService {
    public void save();
}
public class BookServiceImpl implements BookService {
    public void save() {
        System.out.println("book service save ...");

步骤1:在实现类上添加注解

在Dao上添加注解

@Component("bookDao")
public class BookDaoImpl implements BookDao {
...

在Service上添加注解

@Component
public class BookServiceImpl implements BookService {
...

步骤2:创建配置类

创建一个配置类SpringConfig

步骤3:标识该类为配置类

在配置类上添加@Configuration注解

@Configuration
public class SpringConfig {
}

步骤4:用注解替换包扫描配置

在配置类上添加包扫描注解@ComponentScan

@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
}

步骤5:创建运行类并执行

创建一个新的运行类 AppForAnnotation

public class AppForAnnotation {
    public static void main(String[] args) {
        ApplicationContext ctx = new
                AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        System.out.println(bookDao);
        BookService bookService = ctx.getBean(BookService.class);
        System.out.println(bookService);
    }
}

运行

在这里插入图片描述

1.2 小结

  1. Spring对于Bean的管理有四种注解,分别为:
  • @Component
    • @Controller
    • @Service
    • @Repository
  1. ClassPathXmlApplicationContext是加载XML配置文件,AnnotationConfigApplicationContext是加载配置类

  2. 想要把实现类变为非单例,只需要添加注解scope即可,例如:

@Repository
@Scope("prototype")
public class BookDaoImpl implements BookDao {
...
  1. 配置文件与配置类的对比

在这里插入图片描述

二、注解开发依赖注入

Spring为了使用注解简化开发,并没有提供构造函数注入、setter注入对应的注解,只提供了自动装配的注解实现。

2.1 自动装配

2.1.1 @Autowired——按照类型注入

(1)准备工作:

创建Maven项目,添加Spring依赖
添加一个配置类SpringConfig
添加BookDao、BookDaoImpl、BookService、BookServiceImpl类,其中BookDaoImpl添加@Repository注解,BookServiceImpl添加@Service注解
BookServiceImpl如下:
在这里插入图片描述
创建运行类App,运行
在这里插入图片描述

出现问题:NullPointerException:Cannot invoke “com.itheima.dao.BookDao.save()” because “this.bookDao” is null

(2)原因

虽然在BookServiceImpl类中添加了BookDao的属性,并提供了setter方法,但是目前是没有提供配置注入BookDao的,所以bookDao对象为Null,调用其save方法就会报控指针异常。

(3)解决

在BookServiceImpl 类的 bookDao 属性上添加 @Autowired 注解,实现自动装配

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    private BookDao bookDao;
    ...

这样,运行就可以成功了!

(4)小结

@Autowired 可以写在属性上,也可也写在 setter 方法上,最简单的处理方式是 写在属性上并将
setter方法删除

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    private BookDao bookDao;
 
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}
  • 为什么 setter 方法可以删除呢 ?

自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值, 普通反射只能获取 public 修饰的内容, 暴力反射除了获取 public 修饰的内容,还可以获取 private 修改的内容, 所以此处无需提供 setter 方法。

  • @Autowired 是按照类型注入,那么对应 BookDao 接口如果有多个实现类,比如添加BookDaoImpl2,情况就会不同。例如:

    • ①BookDaoImpl和BookDaoImpl2都只添加了注解@Repository,运行就会报错,因为按照类型注入无法区分按照哪个注入

    • ② BookDaoImpl和BookDaoImpl2分别添加了注解@Repository(“bookDao”),@Repository(“bookDao2”),虽然还是有两个Bean对象,但因为变量名叫bookDao,而容器中也只有一个bookDao,所以可以注入成功。

    • ③ BookDaoImpl和BookDaoImpl2分别添加了注解@Repository(“bookDao1”),@Repository(“bookDao2”),因为按照类型有多个Bean对象,此时按照名称bookDao去找,找不到,会报错。

    • 有多个Bean对象,一般选择“按照名称注入”

2.1.2 @Qualifier——按照名称注入

    如果根据类型找到了多个Bean对象,就可以使用@Qualifier指定注入哪个名称的Bean对象
@Service
public class BookServiceImpl implements BookService {
    @Autowired
    @Qualifier("bookDao1")
    private BookDao bookDao;
 
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

注意:@Qualifier不能独立使用,必须和@Autowired一起使用

2.1.3 @Value——简单类型注入

@Repository("bookDao1")
public class BookDaoImpl implements BookDao {
    @Value("itheima")
    private String name;
    ...

此处的@Value并不是无用功,@Value一般会被用在从properties配置文件中读取内容进行使用。

2.2 注解读取properties配置文件——@PropertySource

步骤1:resource下准备properties文件【jdbc.properties】
在这里插入图片描述
步骤2:使用注解加载properties配置文件

@Configuration
@ComponentScan("com.itheima")
@PropertySource("jdbc.properties")
public class SpringConfig {
}

步骤3:使用@Value读取配置文件中的内容

@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    @Value("${name}")
    private String name;
 
    public void save() {
        System.out.println("book dao save ..." + name);
    }
}

运行
在这里插入图片描述
注意:

如果读取的properties配置文件有多个,可以使用@PropertySource的属性来指定多个,

  • @PropertySource({“jdbc.properties”,“xxx.properties”})
  • @PropertySource 注解属性中不支持使用通配符 * , 运行会报错

三、注解开发管理第三方Bean——@Bean

例如,在一个环境中完成对 Druid 数据源的管理,具体步骤为:
步骤1:导入对应的jar包

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.16</version>
</dependency>

步骤2:在配置类中添加方法——@Import

  • 第一种:直接在配置类SpringConfig中书写
@Configuration
public class SpringConfig {
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}

(不推荐)

  • 第二种:引入外部配置类——@Import

如果把所有的第三方bean都配置到Spring的配置类SpringConfig中,会不利于代码阅读和分类管理,我们可以新建一个JdbcConfig配置类,并把数据源配置到该类下

public class JdbcConfig {
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}

然后在SpringConfig中通过@Import注解手动导入需要加载的配置类即可

@Configuration
@Import({JdbcConfig.class})
public class SpringConfig {
}

注意:

  • @Import参数需要的是一个数组,可以引入多个配置类。
  • @Import注解在配置类中只能写一次

当然,我们不建议将数据库的四要素写死在代码里,可以通过加载配置文件,并使用@Value的形式实现,例如
SpringConfig配置类:

@Configuration
@PropertySource("jdbc.properties")
@Import({JdbcConfig.class})
public class SpringConfig {
}

JdbcConfig配置类

public class JdbcConfig {
@Value("${driver}")
private String driver;
@Value("${url}")
private String url;
@Value("${username}")
private String userName;
@Value("${password}")
private String password;
@Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}

步骤3:在方法上添加@Bean注解

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

@Bean的作用是:

@Bean只用在方法上,并告诉这个方法产生一个Bean对象
这个Bean对象会交给Spring管理
Spring只会调用一次这个方法,随后将这个Bean对象放入容器中管理
步骤4:从IOC容器中获取Bean对象并打印

public class App {
    public static void main(String[] args) {
        AnnotationConfigApplicationCont![ext ctx = new
            AnnotationConfigApplicationContext(SpringConfig.class);
        DataSource dataSource = ctx.getBean(DataSource.class);
        System.out.println(dataSource);
    }
}](https://i-blog.csdnimg.cn/direct/46d049698c7b493bb7351edc146bdc70.png)

四、注解开发总结

XML 配置和注解的开发实现之间的差异如图:

在这里插入图片描述

原文链接:https://blog.youkuaiyun.com/qq_45832961/article/details/129041088

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值