Spring IOC/DI注解开发

发布时间 2023-10-17 15:09:09作者: 10kcheung

1 注解开发定义bean

//注解开发定义bean用的是2.5版提供的注解,使用注解代替bean标签。

(1) 删除原XML配置

//将配置文件中的<bean>标签删除掉。
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

(2) Dao上添加注解

//在BookDaoImpl类上添加 @Component注解

@Component("bookDao")
//Bean可以不写名称,即:@Component。
//@Component注解如果不起名称,会有一个默认值就是 当前类名首字母小写,所以也可以按照名称获取:getBean("bookServiceImpl");
//注意:@Component注解不可以添加在接口上,因为接口是无法创建对象的。
//@Component代替了Bean标签,将@Component置于实现类上代替了class属性,@Component中value的值代替了id属性。
//component:组件,Spring将管理的bean视作自己的一个组件。
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("BookDao_save" );
    }
}

(3) 配置Spring的注解包扫描

//为了让Spring框架能够扫描到写在类上的注解,需要在配置文件上进行包扫描。
<context:component-scan base-package="com.itheima"/>
//为了告知配置文件component组件所在的位置
//base-package指定Spring框架扫描的包路径,它会扫描指定包及其子包中的所有类上的注解。
//包路径越多[如:com.itheima.dao.impl],扫描的范围越小速度越快;包路径越少[如:com.itheima],扫描的范围越大速度越慢。
//一般扫描到项目的组织名称即Maven的groupId下[如:com.itheima]即可。

(4) 运行程序

//运行App类查看打印结果
//对于@Component注解,还衍生出了其他三个注解 @Controller、 @Service、 @Repository,这三个注解和@Component注解的作用是一样的,方便我们后期在编写类的时候能很好的区分出这个类是属于表现层、 业务层还是数据层的类。

 

2 纯注解开发模式

//纯注解开发用的是3.0版提供的注解,使用Java类替代配置文件。

(1) 创建配置类

//Java类替换Spring核心配置文件,在com.itheima.config包下创建一个配置类SpringConfig。

public class SpringConfig {
}

(2) 标识该类为配置类

//在配置类上添加@Configuration注解,将其标识为一个配置类,替换applicationContext.xml。

@Configuration
//@Configuration注解基本替代了Spring配置文件。
public class SpringConfig {
}

(3) 用注解替换包扫描配置

//在配置类上添加包扫描注解@ComponentScan替换<context:component-scan base-package=""/>

//@ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据用数组格式,@ComponentScan({com.itheima.service","com.itheima.dao"})。
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
}

(4) 创建运行类并执行

//创建一个新的运行类AppForAnnotation。

public class AppForAnnotation {
    public static void main(String[] args) {
        //因为核心配置文件已经被java类所替换,读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象。
        AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(SpringConfig.class);
        //注意:参数是类而非字符串。
        //ClassPathXmlApplicationContext是加载XML配置文件,AnnotationConfigApplicationContext是加载配置类。
        BookDao bookDao = (BookDao) acac.getBean("bookDao");
        System.out.println(bookDao);
    }
}

 

3 注解开发bean作用范围与生命周期管理

(1) Bean的作用范围

@Repository
//@Scope设置bean的作用范围
@Scope("prototype/singleton")
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("BookDao_save");
    }
}

(2) Bean的生命周期

<1> 在BookDaoImpl中添加两个方法,init和destroy,方法名可以任意。

@Repository
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("BookDao_save");
    }
    public void init() {
        System.out.println("BookDao_init");
    }
    public void destroy() {
        System.out.println("BookDao_destroy");
    }
}

<2> 在对应的方法上添加@PostConstruct和@PreDestroy注解

@Repository
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("BookDao_save");
    }
    @PostConstruct
    //在构造方法之后执行,替换bean标签中的init-method属性。
    public void init() {
        System.out.println("BookDao_init");
    }
    @PreDestroy
    //在销毁方法之前执行,替换bean标签中的destroy-method属性。
    public void destroy() {
        System.out.println("BookDao_destroy");
    }
}

<3> 创建运行类并执行
//创建一个新的运行类AppForAnnotation。

public class AppForAnnotation {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao = (BookDao) acac.getBean("bookDao");
        System.out.println(bookDao);
        acac.close();//关闭容器
    }
}

<4> 注意:@PostConstruct和@PreDestroy注解如果找不到,需要导入下面的jar包。
//找不到的原因是,从JDK9以后jdk中的javax.annotation包被移除了,这两个注解刚好就在这个包中。

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

 

4 注解开发依赖注入

(1) 注解实现按照类型注入

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    //@Autowired可以写在属性上,也可也写在setter方法上,最简单的处理方式是 写在属性上并将setter方法删除掉。
    //@Autowired默认按照类型自动装配,如果IOC容器中同类的Bean找到多个,就按照变量名和Bean的id匹配。若不存在匹配的id则会报 NoUniqueBeanDefinitionException。
    private BookDao bookDao;

    public void save() {
        System.out.println("BookService_save");
        bookDao.save();
    }
}

(2) 注解实现按照名称注入

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    //自动装配时首先根据数据类型来装配,若有多个匹配的数据类型,然后根据bean的id来装配。
    @Qualifier("bookDao1")
    //若每个bean名称都不匹配,最后再根据@Qualifier的value来匹配,@Qualifier注解后的值就是需要注入的bean的id。
    //注意:@Qualifier不能独立使用,必须和@Autowired一起使用
    private BookDao bookDao;

    public void save() {
        System.out.println("BookService_save");
        bookDao.save();
    }
}

(3) 简单数据类型注入

@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    @Value("itheima")
    //@Value一般会被用在从properties配置文件中读取内容进行使用。
    private String name;

    public void save() {
        System.out.println("BookDao_save_" + name);
    }
}

(4) 注解读取properties配置文件

<1> resource目录下准备properties文件
//jdbc.properties
name=itheima
<2> 使用注解加载properties配置文件
//在配置类上添加 @PropertySource注解

@Configuration
@ComponentScan("com.itheima")
@PropertySource("jdbc.properties")
//自动在resource文件夹下读取配置文件。
public class SpringConfig {
}

<3> 使用@Value读取配置文件中的内容

@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    @Value("${name}")
    private String name;

    public void save() {
        System.out.println("BookDao_save_" + name);
    }
}

<4> 运行程序
运行App类,查看运行结果。
<5> 注意
<5.1> 如果读取的properties配置文件有多个,可以使用 @PropertySource的属性来指定多个。
@PropertySource({"jdbc1.properties","jdbc2.properties"})
<5.2> @PropertySource注解属性中不支持使用通配符*,运行会报错。
@PropertySource({"*.properties"})
<5.3> @PropertySource注解属性中可以把 classpath:加上,代表从当前项目的根路径找文件。
@PropertySource({"classpath:jdbc.properties"})