Spring 注解开发
- 注解开发简介
-
常用注解
- 启用注解功能
- bean 定义:@Component、@Controller、@Service、@Repository
- bean 的引用类型属性注入:@Autowired、@Qualifier
- bean 的引用类型属性注入:@Inject、@Named、@Resource
- bean 的引用类型属性注入:@Primary
- bean 的非引用类型属性注入:@Value
- bean 的作用域:@Scope
- bean 的生命周期:@PostConstruct、@PreDestroy
- 加载第三方资源:@Bean
- 加载 properties 文件:@PropertySource
- 纯注解开发:@Configuration、@ComponentScan
- 导入第三方配置:@Import
-
综合案例
- spring 配置类
- dao 层
- service 层
- controller 层
-
整合第三方技术
- 注解整合 Mybatis
- 注解整合 Junit
-
IoC 底层核心原理
- IoC 核心接口
-
组件扫描器:@ComponentScan
- 配置扫描器
- 自定义扫描器
- 自定义导入器:ImportSelector
- 自定义注册器:ImportBeanDefinitionRegistrar
-
bean 初始化过程解析
- bean 统一初始化
- 单个 bean 初始化
注解开发简介
注解开发的好处:使用注解的形式替代 xml 配置,将繁杂的 Spring 配置文件从工程中彻底消除掉,简化书写
。
注解驱动的弊端:
-
为了达成注解驱动的目的,可能会将原先很简单的书写,变得更加复杂。
-
XML 中配置第三方开发的资源是很方便的,但使用注解驱动无法在第三方开发的资源中进行编辑,因此会增大开发工作量。
常用注解
Spring 原始注解:主要是替代 <Bean> 的配置。
注解 | 说明 |
---|---|
@Component | 使用在类上用于实例化 Bean |
@Controller | 使用在 web 层类上用于实例化 Bean |
@Service | 使用在 service 层类上用于实例化 Bean |
@Repository | 使用在 dao 层类上用于实例化 Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合 @Autowired 一起使用,用于根据名称进行依赖注入引用类型 |
@Resource | 相当于 @Autowired + @Qualifier,按照名称进行注入引用类型 |
@Value | 注入普通类型的属性 |
@Scope | 标注 Bean 的作用范围 |
@PostConstruct | 使用在方法上标注该方法是 Bean 的初始化方法 |
@PreDestroy | 使用在方法上标注该方法是 Bean 的销毁方法 |
Spring 新注解:
使用上面的注解还不能全部替代 xml 配置文件,还需要使用注解替代的配置如下:
- 非自定义的Bean的配置:<bean>
- 加载properties文件的配置:<context:property-placeholder>
- 组件扫描的配置:<context:component-scan>
- 引入其他文件:<import>
注解 | 说明 |
---|---|
@Configuration | 用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解。用于指定 Spring 在初始化容器时要扫描的包。 |
@ComponentScan | 作用和在 Spring 的 xml 配置文件中的 <context:component-scan base-package="域名ima"/> 一样。 |
@Bean | 使用在方法上,标注将该方法的返回值存储到 Spring 容器中。 |
@PropertySource | 用于加载 .properties 文件中的配置。 |
@Import | 用于导入其他配置类。 |
启用注解功能
- 启动注解扫描,加载类中配置的注解项:
<context:component-scan base-package="packageName"/>
-
说明:
-
在进行包所扫描时,会对配置的包及其子包中所有文件进行扫描。
-
扫描过程是以文件夹递归迭代的形式进行的。
-
扫描过程仅读取合法的 java 文件。
-
扫描时仅读取 spring 可识别的注解。
-
扫描结束后会将可识别的有效注解转化为 spring 对应的资源加入 IoC 容器。
-
-
注意:
-
无论是注解格式还是 XML 配置格式,最终都是将资源加载到 IoC 容器中,差别仅仅是数据读取方式不同。
-
从加载效率上来说,注解优于 XML 配置文件。
-
bean 定义:@Component、@Controller、@Service、@Repository
-
类型:类注解
-
位置:类定义上方。
-
作用:设置该类为 spring 管理的 bean 。
-
示例:
@Component
public class ClassName{}
-
说明:@Controller、@Service 、@Repository 是 @Component 的衍生注解,功能同 @Component 。
-
相关属性:
- value(默认) :定义 bean 的访问 id 。
bean 的引用类型属性注入:@Autowired、@Qualifier
-
类型:属性注解、方法注解
-
位置:属性定义上方,方法定义上方。
-
作用:设置对应属性的对象或对方法进行引用类型传参。
-
说明:@Autowired 默认按类型装配,指定 @Qualifier 后则可以指定装配的 bean 的 id 。
-
相关属性:
- required:定义该属性是否允许为 null 。
bean 的引用类型属性注入:@Inject、@Named、@Resource
-
说明:
- @Inject 与 @Named 是 JSR330 规范中的注解,功能与 @Autowired 和 @Qualifier 完全相同,适用于不同架构场景。
- @Resource 是 JSR250 规范中的注解,可以简化书写格式。
-
@Resource 相关属性:
-
name:设置注入的 bean 的 id 。
-
type:设置注入的 bean 的类型,接收的参数为 Class 类型。
-
bean 的引用类型属性注入:@Primary
-
类型:类注解
-
位置:类定义上方。
-
作用:设置类对应的bean按类型装配时优先装配。
-
说明:@Autowired 默认按类型装配,当出现相同类型的 bean,使用 @Primary 会提高按类型自动装配的优先级,但多个 @Primary 会导致优先级设置无效。
bean 的非引用类型属性注入:@Value
-
类型:属性注解、方法注解
-
位置:属性定义上方,方法定义上方。
-
作用:设置对应属性的值或对方法进行传参。
-
说明:
-
value 值仅支持非引用类型数据,赋值时对方法的所有参数全部赋值。
-
value 值支持读取 properties 文件中的属性值,通过类属性将 properties 中数据传入类中。
-
value 值支持 SpEL 。
-
@value 注解如果添加在属性上方,可以省略 set 方法(set 方法的目的是为属性赋值)。
-
bean 的作用域:@Scope
-
类型:类注解
-
位置:类定义上方。
-
作用:设置该类作为 bean 对应的 scope 属性。
-
相关属性
- value(默认):定义 bean 的作用域,默认为 singleton 。
bean 的生命周期:@PostConstruct、@PreDestroy
-
类型:方法注解
-
位置:方法定义上方。
-
作用:设置该类作为 bean 对应的生命周期方法。
加载第三方资源:@Bean
-
类型:方法注解
-
位置:方法定义上方。
-
作用:设置该方法的返回值作为 spring 管理的 bean 。
-
范例:
@Bean("dataSource")
public DruidDataSource createDataSource() { return ……; }
-
说明:
-
因为第三方 bean 无法在其源码上进行修改,因此可以使用 @Bean 解决第三方 bean 的引入问题。
-
该注解用于替代 XML 配置中的静态工厂与实例工厂创建 bean,不区分方法是否为静态或非静态。
-
@Bean 所在的类必须被 spring 扫描加载,否则该注解无法生效。
-
-
相关属性
- value(默认):定义 bean 的访问 id 。
加载 properties 文件:@PropertySource
-
类型:类注解
-
位置:类定义上方。
-
作用:加载 properties 文件中的属性值。
-
范例:
@PropertySource(value="classpath:域名erties")
public class ClassName {
@Value("${propertiesAttributeName}")
private String attributeName;
}
-
说明:不支持*通配格式,一旦加载,所有 spring 控制的 bean 中均可使用对应属性值
-
相关属性
-
value(默认):设置加载的 properties 文件名。
-
ignoreResourceNotFound:如果资源未找到,是否忽略,默认为 false 。
-
纯注解开发:@Configuration、@ComponentScan
-
类型:类注解
-
位置:类定义上方。
-
作用:设置当前类为 spring 核心配置加载类(不再需要 spring 配置文件)。
-
范例:
@Configuration
@ComponentScan("scanPackageName")
public class SpringConfigClassName{
}
- 说明:
- 核心配合类用于替换 spring 核心配置文件,此类可以设置空的,不设置变量与属性。
- bean 扫描工作使用注解 @ComponentScan 替代。
- 加载纯注解格式上下文对象,需要使用 AnnotationConfigApplicationContext:
```java
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(域名s);
导入第三方配置:@Import
-
类型:类注解
-
位置:类定义上方。
-
作用:导入第三方 bean 作为 spring 控制的资源。
-
范例:
@Configuration
@Import(域名s)
public class ClassName {
}
-
说明:
-
@Import 注解在同一个类上,仅允许添加一次,如果需要导入多个,使用数组的形式进行设定。
-
在被导入的类中可以继续使用 @Import 导入其他资源(了解)。
-
@Bean 所在的类可以使用导入的形式进入 spring 容器,无需声明为 bean 。
-
综合案例
maven 依赖:
<dependencies>
<dependency>
<groupId>域名ngframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.域名ASE</version>
</dependency>
<dependency>
<groupId>域名aba</groupId>
<artifactId>druid</artifactId>
<version>域名</version>
</dependency>
</dependencies>
spring 配置类
域名:
package 域名ig;
import 域名域名dDataSource;
import 域名域名域名e;
import 域名域名;
import 域名域名ertySource;
// 数据源配置类
// 相当于 <context:property-placeholder location="classpath:域名erties"/>,且不能用通配符*
@PropertySource("classpath:域名erties")
public class DataSourceConfig {
@Value("${域名er}")
private static String driver;
@Value("${域名}")
private static String url;
@Value("${域名name}")
private static String username;
@Value("${域名word}")
private static String password;
@Bean("dataSource") // 将方法的返回值放置Spring容器中
public static DruidDataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
域名riverClassName(driver);
域名rl(url);
域名sername(username);
域名assword(password);
return dataSource;
}
}
域名:
package 域名ig;
import 域名域名onentScan;
import 域名域名iguration;
import 域名域名rt;
// Spring核心配置类
@Configuration
@ComponentScan("com") // 相当于 <context:component-scan base-package="com"/>
@Import({域名s}) // 相当于 <import resource=""/>
public class SpringConfig {
}
dao 层
域名:
package 域名;
import 域名Dao;
import 域名域名onent;
import 域名域名sitory;
// 相当于 <bean id="UserDao" ref="域名.UserDaoImpl"/>
// @Component("userDao")
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void save() {
域名tln("UserDao save...");
}
}
service 层
域名:
package 域名;
import 域名Dao;
import 域名Service;
import 域名域名域名wired;
import 域名域名域名ifier;
import 域名域名域名e;
import 域名域名onent;
import 域名域名ice;
import 域名Construct;
import 域名estroy;
import 域名urce;
import 域名Source;
// 相当于 <bean id="UserService" ref="域名.UserServiceImpl"/>
// @Component("userService")
@Service("userService")
public class UserServiceImpl implements UserService {
// <property name="userDao" ref="userDao"></property>
// @Autowired // 可单独使用,按照数据类型从spring容器中进行匹配的(有多个相同数据类型的bean时则会有匹配问题)
// @Qualifier("userDao") // 指定bean的id从spring容器中匹配,且要结合@Autowired一起用
@Resource(name="userDao") // 相当于 @Autowired+@Autowired
UserDao userDao;
@Resource(name="dataSource")
DataSource dataSource;
@Value("${域名er}") // 读取配置文件中的值
private String driver;
/* 使用注解开发可以省略set方法,使用配置文件则不能省略
public void setUserDao(UserDao userDao) {
域名Dao = userDao;
}
*/
@Override
public void save() {
域名tln("driver: "+driver);
域名tln("dataSource: "+dataSource);
域名();
}
@PostConstruct
public void init() {
域名tln("service对象的初始化方法");
}
@PreDestroy
public void destroy() {
域名tln("service对象的销毁方法");
}
}
controller 层
域名:
package 域名roller;
import 域名ngConfig;
import 域名Service;
import 域名域名icationContext;
import 域名域名tationConfigApplicationContext;
public class App {
public static void main(String[] args) {
// ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("域名");
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(域名s);
UserService userService = (UserService)域名ean("userService");
域名();
域名e();
}
}
运行结果:
service对象的初始化方法
dataSource: {
CreateTime:"2021-12-03 01:05:00",
ActiveCount:0,
PoolingCount:0,
CreateCount:0,
DestroyCount:0,
CloseCount:0,
ConnectCount:0,
Connections:[
]
}
UserDao save...
service对象的销毁方法
整合第三方技术
注解整合 Mybatis
注解整合 MyBatis 的开发步骤:
- 修改 mybatis 外部配置文件格式为注解格式;
- 业务类使用 @Component 声明 bean,使用 @Autowired 注入对象;
- 建立配置文件 JDBCConfig 与 MyBatisConfig 类,并将其导入到核心配置类 SpringConfig;
- 开启注解扫描;
- 使用 AnnotationConfigApplicationContext 对象加载配置项。
项目工程地址
核心内容如下:
- Maven 依赖:
<dependency>
<groupId>域名ngframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.域名ASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>域名</version>
</dependency>
<dependency>
<groupId>域名ngframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.域名ASE</version>
</dependency>
<dependency>
<groupId>域名aba</groupId>
<artifactId>druid</artifactId>
<version>域名</version>
</dependency>
<dependency>
<groupId>域名tis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>域名tis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
- 域名(Mybatis 配置类):
package 域名ig;
import 域名域名essionFactoryBean;
import 域名域名erScannerConfigurer;
import 域名域名域名wired;
import 域名域名;
import 域名Source;
public class MybatisConfig {
/*
<!-- spring整合mybatis后,创建连接用的对象 -->
<bean class="域名域名essionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="域名in"/>
</bean>
<!-- 扫描mybatis映射配置,将其作为spring的bean进行管理 -->
<bean class="域名域名erScannerConfigurer">
<property name="basePackage" value="域名"/>
</bean>
*/
// 以下注解代替以上配置文件内容:返回值会作为Spring容器的bean
@Bean
public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
域名ataSource(dataSource);
域名ypeAliasesPackage("域名in");
return sqlSessionFactoryBean;
}
@Bean
public MapperScannerConfigurer getMapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
域名asePackage("域名");
return mapperScannerConfigurer;
}
}
- 域名(Spring 核心配置类):
package 域名ig;
import 域名域名onentScan;
import 域名域名iguration;
import 域名域名rt;
@Configuration
@ComponentScan("com") // 相当于 <context:component-scan base-package="com"/>
@Import({域名s, 域名s}) // 相当于 <import resource=""/>
public class SpringConfig {
}
注解整合 Junit
注解整合 Junit 的开发步骤:
- Spring 接管 Junit 的运行权,使用 Spring 专用的 Junit 类加载器;
2.为 Junit 测试用例设定对应的 Spring 容器:
-
从 Spring 5.0 以后,要求 Junit 的版本必须是 域名 或以上。
-
Junit 仅用于单元测试,不能将 Junit 的测试类配置成 Spring 的 bean,否则该配置将会被打包进入工程中。
示例:整合 Junit5
- Maven 依赖:
<dependency>
<groupId>域名ter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>域名ngframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.域名ASE</version>
</dependency>
- 测试类:
package 域名ice;
import 域名ngConfig;
import 域名;
import 域名域名rtions;
import 域名域名;
import 域名域名域名ndWith;
import 域名域名域名wired;
import 域名.域名extConfiguration;
import 域名.域名域名ngExtension;
import 域名;
// 设定spring专用的类加载器
@ExtendWith(域名s)
// 设定加载的spring上下文对应的配置
@ContextConfiguration(classes=域名s)
public class UserServiceTest {
@Autowired
UserService userService;
@Test
public void testFindById() {
User user = 域名ById(1);
// 域名tln(user);
域名rtEquals("Mick", 域名ame());
}
@Test
public void testFindAll() {
List<User> users = 域名All();
域名rtEquals(3, 域名());
}
}
IoC 底层核心原理
IoC 核心接口
组件扫描器:@ComponentScan
组件扫描器:开发过程中,需要根据需求加载必要的 bean 或排除指定 bean。
应用场景:
- 数据层接口测试
- 业务层接口测试
- 各种运行环境设置
配置扫描器
-
名称:@ComponentScan
-
类型:类注解
-
位置:类定义上方
-
作用:设置 spring 配置加载类扫描规则
-
范例:
@Configuration
@ComponentScan(
value="com", // 设置基础扫描路径
excludeFilters = // 设置过滤规则,当前为排除过滤
@域名er( // 设置过滤器
type= 域名TATION, // 设置过滤方式为按照注解进行过滤
classes=域名s) // 设置具体的过滤项。如不加载所有@Repository修饰的bean
)
public class SpringConfig {
}
-
includeFilters:设置包含性过滤器
-
excludeFilters:设置排除性过滤器
-
type:设置过滤器类型(过滤策略)
- ANNOTATION
- ASSIGNABLE_TYPE
- ASPECTJ
- REGEX
- CUSTOM
自定义扫描器
-
名称:TypeFilter
-
类型:接口
-
作用:自定义类型过滤器
示例:
- 自定义扫描器
public class MyTypeFilter implements TypeFilter {
public boolean match(MetadataReader mr, MetadataReaderFactory mrf) throws IOException {
ClassMetadata cm = 域名lassMetadata();
tring className = 域名lassName();
if(域名ls("域名.域名DaoImpl")){
return true; // 进行过滤(拦截)
}
return false; // 不过滤(放行)
}
}
- 配置类:
@Configuration
@ComponentScan(
value = "com",
excludeFilters = @域名er(
type= 域名OM,
classes = 域名s
)
)
public class SpringConfig {
}
自定义导入器:ImportSelector
bean 只有通过配置才可以进入 spring 容器,被 spring 加载并控制。配置 bean 的方式如下:
-
XML 文件中使用 <bean/> 标签配置
-
使用 @Component 及衍生注解配置
企业开发过程中,通常需要配置大量的 bean,因此需要一种快速高效配置大量 bean 的方式。
ImportSelector 注解:
-
类型:接口
-
作用:自定义 bean 导入器(导入未加 @Component 注解的 bean)
示例:
- 自定义导入器:
public class MyImportSelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata icm) {
// 返回需要导入的bean数组。该bean即使没加@Component注解也能被扫描识别
return new String[]{"域名.AccountDaoImpl"};
}
}
- 配置类:
@Configuration
@ComponentScan("com")
@Import(域名s) // 导入自定义导入器
public class SpringConfig {
}
自定义导入器的封装工具类:
import 域名域名sPathScanningCandidateComponentProvider;
import 域名域名onentScan;
import 域名域名rtSelector;
import 域名.域名ertiesLoaderUtils;
import 域名.域名tationMetadata;
import 域名.域名ctJTypeFilter;
import 域名.域名Filter;
import 域名ception;
import 域名Set;
import 域名;
import 域名erties;
import 域名;
public class CustomerImportSelector implements ImportSelector {
private String expression;
public CustomerImportSelector(){
try {
//初始化时指定加载的properties文件名
Properties loadAllProperties = 域名AllProperties("域名erties");
//设定加载的属性名
expression = 域名roperty("path");
} catch (IOException e) {
// TODO Auto-generated catch block
域名tStackTrace();
}
}
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//1.定义扫描包的名称
String[] basePackages = null;
//2.判断有@Import注解的类上是否有@ComponentScan注解
if (域名nnotation(域名ame())) {
//3.取出@ComponentScan注解的属性
Map<String, Object> annotationAttributes = 域名nnotationAttributes(域名ame());
//4.取出属性名称为basePackages属性的值
basePackages = (String[]) 域名("basePackages");
}
//5.判断是否有此属性(如果没有ComponentScan注解则属性值为null,如果有ComponentScan注解,则basePackages默认为空数组)
if (basePackages == null || 域名th == 0) {
String basePackage = null;
try {
//6.取出包含@Import注解类的包名
basePackage = 域名ame(域名lassName()).getPackage().getName();
} catch (ClassNotFoundException e) {
域名tStackTrace();
}
//7.存入数组中
basePackages = new String[] {basePackage};
}
//8.创建类路径扫描器
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
//9.创建类型过滤器(此处使用切入点表达式类型过滤器)
TypeFilter typeFilter = new AspectJTypeFilter(expression,域名lass().getClassLoader());
//10.给扫描器加入类型过滤器
域名ncludeFilter(typeFilter);
//11.创建存放全限定类名的集合
Set<String> classes = new HashSet<>();
//12.填充集合数据
for (String basePackage : basePackages) {
域名CandidateComponents(basePackage).forEach(beanDefinition -> 域名(域名eanClassName()));
}
//13.按照规则返回
return 域名ray(new String[域名()]);
}
}
自定义注册器:ImportBeanDefinitionRegistrar
-
类型:接口
-
作用:自定义 bean 定义注册器(识别标记了 @Component 的 bean)
示例:
- 自定义注册器:
// 表示com目录下的bean全部注册
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata icm, BeanDefinitionRegistry r) {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(r, false);
TypeFilter tf = new TypeFilter() {
public boolean match(MetadataReader mr, MetadataReaderFactory mrf) throws IOException {
return true;
}
};
域名ncludeFilter(tf); // 包含
// 域名xcludeFilter(tf); // 排除
域名("com");
}
}
- 配置类:
@Configuration
@Import(域名s) // 作用等同于 @ComponentScan("com")
public class SpringConfig {
}
封装工具类:
import 域名域名域名DefinitionRegistry;
import 域名域名sPathBeanDefinitionScanner;
import 域名域名onentScan;
import 域名域名rtBeanDefinitionRegistrar;
import 域名.域名ertiesLoaderUtils;
import 域名.域名tationMetadata;
import 域名.域名ctJTypeFilter;
import 域名.域名Filter;
import 域名ception;
import 域名;
import 域名erties;
public class CustomeImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
private String expression;
public CustomeImportBeanDefinitionRegistrar(){
try {
//初始化时指定加载的properties文件名
Properties loadAllProperties = 域名AllProperties("域名erties");
//设定加载的属性名
expression = 域名roperty("path");
} catch (IOException e) {
域名tStackTrace();
}
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//1.定义扫描包的名称
String[] basePackages = null;
//2.判断有@Import注解的类上是否有@ComponentScan注解
if (域名nnotation(域名ame())) {
//3.取出@ComponentScan注解的属性
Map<String, Object> annotationAttributes = 域名nnotationAttributes(域名ame());
//4.取出属性名称为basePackages属性的值
basePackages = (String[]) 域名("basePackages");
}
//5.判断是否有此属性(如果没有ComponentScan注解则属性值为null,如果有ComponentScan注解,则basePackages默认为空数组)
if (basePackages == null || 域名th == 0) {
String basePackage = null;
try {
//6.取出包含@Import注解类的包名
basePackage = 域名ame(域名lassName()).getPackage().getName();
} catch (ClassNotFoundException e) {
域名tStackTrace();
}
//7.存入数组中
basePackages = new String[] {basePackage};
}
//8.创建类路径扫描器
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, false);
//9.创建类型过滤器(此处使用切入点表达式类型过滤器)
TypeFilter typeFilter = new AspectJTypeFilter(expression,域名lass().getClassLoader());
//10.给扫描器加入类型过滤器
域名ncludeFilter(typeFilter);
//11.扫描指定包
域名(basePackages);
}
}
bean 初始化过程解析
bean 统一初始化
-
BeanFactoryPostProcessor
-
作用:定义了在 bean 工厂对象创建后,bean 对象创建前执行的动作,用于对工厂进行创建后业务处理。
-
运行时机:当前操作用于对工厂进行处理,仅运行一次。
-
-
BeanPostProcessor
-
作用:定义了所有 bean 初始化前后进行的统一动作,用于对 bean 进行创建前业务处理与创建后业务处理。
-
运行时机:当前操作伴随着每个 bean 的创建过程,每次创建 bean 均运行该操作。
-
-
InitializingBean
-
作用:定义了每个 bean 的初始化前进行的动作,属于非统一性动作,用于对 bean 进行创建前业务处理。
-
运行时机:当前操作伴随着任意一个 bean 的创建过程,保障其个性化业务处理。
-
-
注意:上述操作均需要被 spring 容器加载方可运行。
示例:
- BeanFactoryPostProcessor:
package 域名;
import 域名域名sException;
import 域名域名域名FactoryPostProcessor;
import 域名域名域名igurableListableBeanFactory;
public class MyBeanFactory implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
域名tln("Bean工厂制作好了");
}
}
- BeanPostProcessor:
package 域名;
import 域名域名sException;
import 域名域名域名PostProcessor;
public class MyBean implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
域名tln("bean之前巴拉巴拉");
域名tln(beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
域名tln("bean之后巴拉巴拉");
return bean;
}
}
- InitializingBean:
package 域名;
import 域名Dao;
import 域名;
import 域名Service;
import 域名域名essionFactoryBean;
import 域名域名ializingBean;
import 域名域名域名wired;
import 域名域名ice;
import 域名urce;
import 域名;
@Service("userService")
public class UserServiceImpl implements InitializingBean {
// 定义当前bean初始化操作,功效等同于init-method属性配置
@Override
public void afterPropertiesSet() throws Exception {
域名tln("UserServiceImpl......bean ...init......");
}
}
- 运行结果:
Bean工厂制作好了
bean之前巴拉巴拉
springConfig
bean之后巴拉巴拉
bean之前巴拉巴拉
域名SourceConfig
bean之后巴拉巴拉
bean之前巴拉巴拉
dataSource
bean之后巴拉巴拉
bean之前巴拉巴拉
getSqlSessionFactoryBean
bean之后巴拉巴拉
bean之后巴拉巴拉
bean之前巴拉巴拉
userDao
bean之后巴拉巴拉
bean之后巴拉巴拉
bean之前巴拉巴拉
userService
UserServiceImpl......bean ...init......
bean之后巴拉巴拉
bean之前巴拉巴拉
域名域名INAL
bean之后巴拉巴拉
单个 bean 初始化
- FactoryBean:对单一的 bean 的初始化过程进行封装,达到简化配置的目的。
FactoryBean 与 BeanFactory 区别:
-
FactoryBean:封装单个 bean 的创建过程。通常是为了创建另一个 bean 而做的准备工作。
-
BeanFactory:Spring 容器顶层接口,统一定义了 bean 相关的获取操作。
示例:
import 域名域名oryBean;
public class UserServiceImplFactoryBean implements FactoryBean {
// 重点:返回数据
@Override
public Object getObject() throws Exception {
return new UserServiceImpl();
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}