spring的注解开发
启动注解功能
启动注解功能
⚫ 启动注解扫描,加载类中配置的注解项
⚫ 说明:
◆ 在进行包所扫描时,会对配置的包及其子包中所有文件进行扫描
◆ 扫描过程是以文件夹递归迭代的形式进行的
◆ 扫描过程仅读取合法的java文件
◆ 扫描时仅读取spring可识别的注解
◆ 扫描结束后会将可识别的有效注解转化为spring对应的资源加入IoC容器
⚫ 注意:
◆ 无论是注解格式还是XML配置格式,最终都是将资源加载到IoC容器中,差别仅仅是数据读取方式不同
◆ 从加载效率上来说注解优于XML配置文件
applicationContext.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
https://www.springframework.org/schema/context/spring-context.xsd">
<!--注解只是一个标记,如果spring不去扫描解析的话,这个标记就不会生效-->
<!-- 启动spring扫描注解的包,只扫描spring的注解-->
<context:component-scan base-package="com.fs"/>
</beans>
将类交给springIOC管理,bean的定义@Component @Controller @Service @Repository
代码解释
package com.fs.demo;
/*
spring注解将类交给spring的ioc管理
*/
import org.springframework.stereotype.Component;
/*
@Component
这个注解就相当于核心配置文件中的
<bean id="类名首字母小写" class="权限定类名"/>
@Component的衍生注解@Controller @Service @Repository,功能和 @Component一样
只是spring对应三层结构来定的注解,功能一样,只是含义不同而已,所以使用其中那一个都可以
将类交给ioc管理
*/
@Component
public class AnnotationDemo {
public AnnotationDemo() {
System.out.println("AnnotationDemo被spring的IOC管理了~~~");
}
public void testMethod(){
System.out.println("测试方法执行~~~");
}
}
测试代码
@Test
public void testOne(){
//创建ioc容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过类名首字母小写从ioc中获取对象
AnnotationDemo annotationDemo = (AnnotationDemo) applicationContext.getBean("annotationDemo");
//使用类.class从ioc中获取对象
AnnotationDemo bean = applicationContext.getBean(AnnotationDemo.class);
//调用方法
annotationDemo.testMethod();
bean.testMethod();
}
bean的作用域(@Scope(“单例或者双列”))(了解)
bean的生命周期
@Bean注解的使用
代码演示
package com.fs.demo;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/*
@Configuration
放在类上,说明这个类是一个spring的配置类
首先这个类要标志是被spring扫描的,才会去扫描这个类下的其他注解@Bean
*/
@Configuration
public class DataSourceDemo {
/*
在方法上@Bean
将方法的返回值交给ioc管理
配置DruidDataSource链接池对象交给ioc管理
*/
@Bean("druidDataSource")//给一个id
public DruidDataSource getDruidDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://192.168.93.132:3306/test");
druidDataSource.setUsername("root");
druidDataSource.setPassword("root");
return druidDataSource;
}
}
测试代码
/*
测试@Bean注入的druid连接池
*/
@Test
public void testDataSource(){
//创建ioc容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过类名首字母小写从ioc中获取对象
DruidDataSource druidDataSource = (DruidDataSource) applicationContext.getBean("druidDataSource");
// DataSource dataSource = (DataSource) applicationContext.getBean(DataSource.class);
DruidDataSource dataSource = applicationContext.getBean(DruidDataSource.class);
// System.out.println(dataSource);
System.out.println(druidDataSource);
}
bean的属性依耐注入DI
代码演示@Value
package com.fs.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
/*
@Value
非引用类型的属性注入
*/
@Component("student")//注入的时候起了个id名
//@Primary//没有起id的时候,这个注解是让这个bean优先加载
public class Student {
/*
@Value
DI依耐注入,给基本类型属性注入值
*/
@Value("18")
private int age;
@Value("小付")
private String name;
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
代码演示@Autowired、@Qualifier
package com.fs.pojo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/*
依耐注入之引用类型的注入
@Autowired
注意:注入的bean一定要在ioc容器中,才能注入
因为这个注解是在ioc容器中去找对应的bean注入
*/
@Component
public class Person{
@Value("男")
private String gender;
/*
@Autowired DI依耐注入
按照类型自动注入(id类名首字母小写)
*/
// @Autowired
// private Student student;
/*
@Autowired
@Qualifier("student")//若有相同类型的,按照id注入
*/
@Autowired
@Qualifier("student")
private Student student;
@Override
public String toString() {
return "Person{" +
"gender='" + gender + '\'' +
", student=" + student +
'}';
}
}
测试代码
/*
测试依耐注入属性
@Autowired
@Qualifier("id")
*/
@Test
public void testDI(){
//创建ioc容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过类名首字母小写从ioc中获取对象
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
/*
输出结果:Person{gender='男', student=Student{age=18, name='小付'}}
*/
}
了解注解
加载类路径下的properties文件@PropertySource
准备properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.93.132:3306/test
jdbc.username=root
jdbc.password=root
代码演示
package com.fs.properties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/*
@PropertySource
引入类路径下的的properties文件
属性:value = "classpath:resource中的properties文件"
*/
@Component//将这个类交给ioc管理
@PropertySource(value = "classpath:jdbc.properties")
public class PropertiesDemo {
//@Value("${Key}")
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Override
public String toString() {
return "PropertiesDemo{" +
"driver='" + driver + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
测试代码
/*
测试@PropertySource(value = "classpath:jdbc.properties")
测试引入类路径下的properties文件
*/
@Test
public void testProperties(){
//创建ioc容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过类名首字母小写从ioc中获取对象
//PropertiesDemo propertiesDemo = (PropertiesDemo) applicationContext.getBean("propertiesDemo");
//通过类名.class
PropertiesDemo propertiesDemo = applicationContext.getBean(PropertiesDemo.class);
System.out.println(propertiesDemo);
//控制台输出结果:
//PropertiesDemo{driver='com.mysql.jdbc.Driver', url='jdbc:mysql://192.168.93.132:3306/test', username='root', password='root'}
}
测底去除配置文件@Configuration、@ComponentScan @Import
我们现在还有applicationContext.xml这个文件,我们可以通过注解来指定一个配置类,从而让配置文件不见
@Import(类.class)配置类上写入后,就会把你给的类存放在IOC容器中,存放的id为类的全限定类名(包名加加类名)
代码演示
package com.fs.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/*
@Configuration
这个注解就表示这是一个配置类
@ComponentScan("com.fs")
这个注解表示spring扫描那些包下的注解
@Import({DataSourceConfig.class})
写在配置类,导入其他的配置类
类.class就可以将这个类注入到spring的ioc容器中
什么类都可以通过@Import({类.class,类2.class})来注入到spring的ioc容器中
*/
@Configuration
@ComponentScan("com.fs")
@Import({DataSourceConfig.class})
public class SpringConfig {
}
测试代码
//使用spring配置类来创建ioc
@Test
public void testSpringConfig(){
//创建ioc容器 AnnotationConfigApplicationContext(配置类.class)
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
//通过类名首字母小写从ioc中获取对象
//PropertiesDemo propertiesDemo = (PropertiesDemo) applicationContext.getBean("propertiesDemo");
//通过类名.class
PropertiesDemo propertiesDemo = applicationContext.getBean(PropertiesDemo.class);
System.out.println(propertiesDemo);
}
/*
测试@Import 导入的druid连接池
*/
@Test
public void testImport(){
//创建ioc容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过类名首字母小写从ioc中获取对象
DruidDataSource druidDataSource = (DruidDataSource) applicationContext.getBean("druidDataSource");
// DataSource dataSource = (DataSource) applicationContext.getBean(DataSource.class);
DruidDataSource dataSource = applicationContext.getBean(DruidDataSource.class);
// System.out.println(dataSource);
System.out.println(druidDataSource);
}
依耐加载
依赖加载应用场景
⚫ @DependsOn
◆微信订阅号,发布消息和订阅消息的bean的加载顺序控制
◆双11活动期间,零点前是结算策略A,零点后是结算策略B,策略B操作的数据为促销数据。策略B
加载顺序与促销数据的加载顺序
⚫ @Lazy
◆程序灾难出现后对应的应急预案处理是启动容器时加载时机
⚫ @Order
◆多个种类的配置出现后,优先加载系统级的,然后加载业务级的,避免细粒度的加载控制