Bean的注解开发

目录

注解定义bean

在实现类使用注解@Component

注意Spring提供了@Component注解的三个衍生注解

纯注解开发

bean管理

 bean的作用范围

bean的生命周期

bean的依赖注入

引用类型的注入 

如果有两个实现类呢(即有两个相同变量类型的bean),那该怎么办?

 简单类型的注入

 配置第三方Bean

获取Bean

抽取出新的配置类


注解定义bean

在实现类使用注解@Component

@Component
public class BookDaoImpl implements BookDao {
    public void update(){
        System.out.println("BookDao");
    }
}

那么spring怎么知道它要被定义成bean,所以在springConfig.xml文件中配置

<?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"
       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
">
    <context:component-scan base-package="com.hhh.dao"></context:component-scan>
</beans>

使用<context:component-scan>标签指定扫描包

public class App {
    public static void main(String[] args) {
        //加载配置文件,初始化容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("springConfig.xml");
        //容器中获取bean
       BookDao bookDao = ctx.getBean(BookDao.class);
       //或者BookDao bookDao = ctx.getBean(BookDaoImpl.class);

        bookDao.update();
    }
}

 除了可以通过类.class的方式来获取bean还可以通过id来获取bean,我们没有在<bean>标签中定义id名,那么对应的bean对象的id名是什么呢?

如果实现类的命名是驼峰式,那么id名就是开头字母小写,如果不是驼峰式,类名就是id名

public class App {
    public static void main(String[] args) {
        //加载配置文件,初始化容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("springConfig.xml");
        //容器中获取bean
       //BookDao bookDao = ctx.getBean(BookDao.class);
       //或者BookDao bookDao = ctx.getBean(BookDaoImpl.class);

        BookDao bookDao= (BookDao) ctx.getBean("bookDaoImpl");

        bookDao.update();
    }
}

 我们也可以直接使用注解@Component的value属性来赋值,值就是id名

@Component("bookDao1")
public class BookDaoImpl implements BookDao {
    public void update(){
        System.out.println("BookDao");
    }
}

public class App {
    public static void main(String[] args) {
        //加载配置文件,初始化容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("springConfig.xml");
        //容器中获取bean
       //BookDao bookDao = ctx.getBean(BookDao.class);
       //或者BookDao bookDao = ctx.getBean(BookDaoImpl.class);

        //BookDao bookDao= (BookDao) ctx.getBean("bookDaoImpl");
        BookDao bookDao= (BookDao) ctx.getBean("bookDao1");

        bookDao.update();
    }
}

注意Spring提供了@Component注解的三个衍生注解

  • @Controller:用于表现层(web)bean的定义
  • @Service:用于业务层(service)bean的定义
  • @Repository:用于数据层(dao)bean的定义
@Repository("bookDao1")
public class BookDaoImpl implements BookDao {
    public void update(){
        System.out.println("BookDao");
    }
}

 

可以发现@Repository其实和@Component注解的功能基本一样,但是这样把三层架构的注解区别,更美观,也更有利于管理 

纯注解开发

spring3.0升级了纯注解开发,使用java类代替配置文件。

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

使用两个注解

@Configuration说明这个类是配置文件

@ComponentScan说明这个配置文件要扫描的包

使用(先把配置文件删除):

public class App {
    public static void main(String[] args) {
        //加载配置文件,初始化容器
        //ApplicationContext ctx=new ClassPathXmlApplicationContext("springConfig.xml");
        //不使用配置文件初始化容器,加载配置类
        ApplicationContext ctx=new AnnotationConfigApplicationContext(SpringConfig.class);

        //容器中获取bean
       //BookDao bookDao = ctx.getBean(BookDao.class);
       //或者BookDao bookDao = ctx.getBean(BookDaoImpl.class);

        //BookDao bookDao= (BookDao) ctx.getBean("bookDaoImpl");
        BookDao bookDao= (BookDao) ctx.getBean("bookDao1");

        bookDao.update();
    }
}

 那如果要扫描两个包呢?

@Configuration
@ComponentScan({"com.hhh.dao","com.hhh.service"})
public class SpringConfig {
}

bean管理

 bean的作用范围

之前我们需要在<bean>标签中的scope属性来配置,现在我们只需要在实现类的开头使用注解@Scope即可

@Repository("bookDao1")
@Scope("prototype")
//多例
public class BookDaoImpl implements BookDao {
    public void update(){
        System.out.println("BookDao");
    }
}

bean的生命周期

在配置文件中我们需要使用init-method,destroy-method来配置初始方法和销毁方法

现在我们只需要用  @PostConstruct定义初始方法,@PreDestroy定义销毁方法

@Repository("bookDao1")
//@Scope("prototype")
public class BookDaoImpl implements BookDao {
    public void update(){
        System.out.println("BookDao");
    }
    @PostConstruct
    public void init(){
        System.out.println("init");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("destroy");
    }
}

如果这两个注解失效,是因为@PostConstruct 和 @PostDestroy 注释都是Java EE的一部分。而且由于Java EE在Java 9中已被弃用,而在Java 11中已被删除

所以只需要在pom.xml中加上

<dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.2</version>
        </dependency>

 使用

public class App {
    public static void main(String[] args) {
        //加载配置文件,初始化容器
        //ApplicationContext ctx=new ClassPathXmlApplicationContext("springConfig.xml");
        //不使用配置文件初始化容器
        AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(SpringConfig.class);

        //容器中获取bean
       //BookDao bookDao = ctx.getBean(BookDao.class);
       //或者BookDao bookDao = ctx.getBean(BookDaoImpl.class);

        //BookDao bookDao= (BookDao) ctx.getBean("bookDaoImpl");
        BookDao bookDao= (BookDao) ctx.getBean("bookDao1");
        bookDao.update();
        ctx.close();
        //bookDao.update();
    }
}

结果:

bean的依赖注入

service层

引用类型的注入 


@Service
public class BookServiceImpl implements BookService {
    @Autowired
    //根据变量类型自动依赖注入
    private BookDao bookDao;
    public void update(){
        bookDao.update();
        System.out.println("BookService");
    }
}

 使用注解@AutoWired即可实现依赖注入,原理是在容器中寻找有没有与这个变量类型一致的bean对象,如果有就直接依赖注入。

可以发现使用注解不用写setter方法,因为直接使用的暴力反射进行赋值

如果有两个实现类呢(即有两个相同变量类型的bean),那该怎么办?

不处理就会报错

No qualifying bean of type 'com.hhh.dao.BookDao' available: expected single matching bean but found 2: bookDao1,bookDaoImpl2
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)

如果有和变量名一致的id(前提:类型一致)那么就可以直接赋值,不会报错

但是使用注解@Qualifier可以直接指定使用哪个bean

注意@Qualifier不可单独使用,必须和@AutoWired一起用

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    @Qualifier("bookDao2")//使用id名为bookDao2的实现类对象
    //根据变量类型自动依赖注入
    private BookDao bookDao;
    public void update(){
        bookDao.update();
        System.out.println("BookService");
    }
}

结果:

 简单类型的注入

使用注解@Value

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    @Qualifier("bookDao2")
    //根据变量类型自动依赖注入
    private BookDao bookDao;
    @Value("hhh")
    private String name;
    @Value("foo,bar,fun")
    private List<String> list;
    public void update(){
        bookDao.update();
        System.out.println("BookService");
        System.out.println("name="+name);
        System.out.println(list);
    }
}

注入外部文件

现在SpringConfig类中添加注解@PropertySource

@Configuration
@ComponentScan({"com.hhh.dao","com.hhh.service"})
@PropertySource("classpath:jdbc.properties")//加载名字为dbc.properties的文件
public class SpringConfig {
}

这是文件的内容

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    @Qualifier("bookDao2")
    //根据变量类型自动依赖注入
    private BookDao bookDao;
    @Value("hhh")
    private String name;
    @Value("foo,bar,fun")
    private List<String> list;
    @Value("${jdbc.username}")//去加载文件的key为username的value值
    private String nm;
    public void update(){
        bookDao.update();
        System.out.println("BookService");
        System.out.println("name="+name);
        System.out.println(list);
        System.out.println(nm);
    }
}

 配置第三方Bean

先导入坐标

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
@Configuration
@ComponentScan({"com.hhh.dao","com.hhh.service"})
@PropertySource("jdbc.properties")
public class SpringConfig {
    @Bean
    public DataSource getDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        return druidDataSource;
    }
}

使用注解@Bean让这个方法的返回值变成Bean(交给Spring容器管理),默认id为方法名

获取Bean


public class App {
    public static void main(String[] args) {
     //不使用配置文件初始化容器
     AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(SpringConfig.class);
        //第一种方法:
        //DataSource dataSource = ctx.getBean(DataSource.class);//使用类
        //第二种方法:使用id名,id名为方法名
        Object dataSource = ctx.getBean("getDataSource");
        System.out.println(dataSource);

    }
}

 或者直接使用@Bean的属性直接配置id名,这样一来id就不是方法名了


@Configuration
@ComponentScan({"com.hhh.dao","com.hhh.service"})
@PropertySource("jdbc.properties")
public class SpringConfig {
    @Bean("dataSource")
    public DataSource getDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        return druidDataSource;
    }
}

抽取出新的配置类

可以发现这是数据源的配置文件,可以把它从Spring的配置文件中抽取出来

然后再SpringConfig类中使用@Import注解导入该文件即可 

@Configuration
@ComponentScan({"com.hhh.dao","com.hhh.service"})
@PropertySource("jdbc.properties")
@Import({jdbcConfig.class})
public class SpringConfig {

}

或者

 直接再jdbcConfig类中直接用@Configuration注解,但是SpringConfig类的@ComponentScan要改成整个包,保证扫描到jdbcConfig类

 配置数据库的四个参数

public class jdbcConfig {
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String name;
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.password}")
    private String password;
    @Bean("dataSource")
    public DataSource getDataSource(){
        System.out.println("driver="+driver);
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(url);
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setName(name);
        druidDataSource.setPassword(password);
        return druidDataSource;
    }
}

使用的是SpringConfig导入了jdbc.properties文件

 如果需要使用引用数据类型,直接再方法里的参数里写,它就会自己注入,不需要@Autowire注解

  • 17
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落落落sss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值