spring bean 的方方面面
bean 属性
<bean id = "" class = "" name = "" scope = "" lazy-init = "" init-method = "" destroy-method = "" autowire ="" depends-on = "" factory-bean = "" factory-method = "" primary = "" profile = "" parent = "">
</bean>
属性 | 作用 | 备注 |
---|---|---|
id | bean 唯一标识符 | 单例池的 key |
class | 类全限定名 | 反射创建这个对象 |
name | bean 别名 | 没啥卵用 |
scope | 作用域 | Singleton:单例(默认) Prototype:原型,每次创建新的 Request:每次 request 使用同一个,web 环境适用 Session:每个 session 使用同一个,web 环境适用 |
lazy-init | 是否延迟加载 | 默认是 false,如果需要延迟加载可以指定为 true 是容器启动就放入单例池,还是在ioc容器获取bean的时候才创建 |
init-method | bean 初始化方法 | 初始化要做很多操作,这只是其中一点 |
destroy-method | bean 销毁方法 | |
autowire | 自动装配的方式 | no:不装配 byName:根据名称装配 byType:根据类型装配 |
depends-on | 指定 bean 的依赖 bean | 指定的 bean 完成装配后才开始装配当前 bean |
factory-bean | 指定工厂 bean 的名称 | 必须搭配 factory-method,工厂方式的非静态方法创建 bean |
factory-method | 指定工厂 bean 的方法 | 可以不搭配 factory-bean 单独使用,工厂方式的静态方法创建 bean |
primary | 首选 bean | 当根据类型能找到多个 bean 的时候,首选这个 bean |
profile | 环境 | 指定的环境中才生成这个 bean,非指定环境不会创建这个 bean |
parent | 指定父级 bean | 这个 bean 会继承父级 bean 的属性 |
工厂方式静态方法创建 bean
<!-- 反射执行 com.mj.center.credit.service.impl.UserServiceImpl 的静态方法 getUserService -->
<bean id="userService"
class="com.mj.center.credit.service.impl.UserServiceImpl"
factory-method="getUserService" />
工厂方式非静态方法创建 bean
<bean id="userService" class="com.mj.center.credit.service.impl.UserServiceImpl" />
<!-- 调用 com.mj.center.credit.service.impl.UserServiceImpl 的普通方法创建 userDao -->
<bean id="userDao" factory-bean="userService" factory-method="getUserDao" />
工厂方式 FactoryBean 创建 bean
<!-- 1,UserServiceFactoryBean 实现 FactoryBean 接口
2,UserServiceFactoryBean 复写 getObject 方法,返回值是真正的 bean
3,如果没有实现 FactoryBean 接口,就会根据构造方法创建普通的 bean
-->
<bean id="userService" class="com.mj.center.credit.service.impl.UserServiceFactoryBean" />
自定义 bean
xml 方式
<bean id="" calss = "">
<property name = "age" value = "18" />
<property name = "userDao" ref = "userDao" />
</bean>
注解方式
@Component(value = "testBean") // bean 定义:id = testBean,class = com.study.TestBean1
@Scope(value = "singleton") // bean 定义:scope = singleton
@Lazy(value = false) // bean 定义:不延迟加载
public class TestBean1 {
// 注入普通属性,字符串、整形、BigDecimal
@Value("18")
private int age;
// 引用其他 bean
@Autowired
private UserDao userDao;
}
非自定义 bean
- 要是用 @Bean 标注某个方法,这个方法的返回值就是真实 bean,可以指定名称,如果不指定默认是方法名
- 方法所在的类要被 spring 管理,所以类上要用 @Component 类似的注解(@Configuration 注解上也是标注了 @Component 的)
// @Configuration、@Service 都行
@Component
public class TestBean2 {
@Scope("prototype")
// 指定初始化和销毁方法(UserDao中必须存在init和cleanup方法)
@Bean(initMethod = "init", destroyMethod = "cleanup")
public UserDao userDao1(){
// 这是真实的 bean
retuen new UserDao();
}
}
配置 bean
<?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:annotation-config/>
<!-- 外部配置文件 -->
<context:property-placeholder location = "classpath:jdbc.properties" />
<!-- 扫描指定的包 -->
<context:component-scan base-package="com.study"/>
<!-- 导入其他配置 -->
<import resource="classpath:DatabaseConfig.xml"/>
<!-- 开启自动代理 -->
<aop:aspectj-autoproxy/>
<!-- 配置 Spring 的声明式事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置 DAO 或 Service Bean -->
<bean id="myService" class="com.example.MyServiceImpl">
</bean>
</beans>
对应的注解配置如下:
@Configuration
@PropertySource("classpath:jdbc.properties")
@ComponentScan("com.study")
@Import(DatabaseConfig.class)
@EnableAspectJAutoProxy
@EnableTransacTionManagement
public class SpringConfig{
}
-
@Configuration
- 标注当前的 bean 是一个配置 bean,代替 spring 上下文的配置文件
- 对应 xml 标签
<context:annotation-config/>
-
@PropertySource
- 读取 properties 文件
- 对应 xml 标签
<context:property-placeholder location = "classpath:jdbc.properties" />
-
@ComponentScan
- 自动扫描包
- 对应 xml 标签
<context:component-scan base-package="com.example"/>
-
@Import
-
导入其他的类到 ioc 容器中,也就是指定一些类,创建这些类的 bean,然后放到单例池。有三种用法:
@Import(A.class) // 导入普通类 @Import(MyImportSelector.class) // 导入实现了 ImportSelector 的类 @Import(MyImportBeanDefinitionRegister.class) // 需实现 ImportBeanDefinitionRegistrar 接口
-
导入普通类
/** * 这是一个普通的类,没有任何注解 */ public class User { private String name; } /** * 直接使用 @Import 导入User类到IOC容器中 */ @Configuration @Import(User.class) public class SpringConfig { public static void main(String[] args) { AnnotationConfigApplicationContext annCtx = new AnnotationConfigApplicationContext(SpringConfig.class); // 这种方式由于未定义 Bean id 和 name, getBean 时只能用类的class去拿或者类的权限定名 User bean = annCtx.getBean(User.class); System.out.println(bean); } }
-
导入实现了 ImportSelector 的类(能批量导入,原理是注册一批 BeanDefinition)
// 一个实现了 ImportSelector 接口的类 public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // 参数 importingClassMetadata 可以获取当前类被 @Import 导入的类的所有注解信息(有点绕看下面) // 返回值是个数组,数组的每一项都会导入 ioc 容器 return new String[]{User.class.getName(), Order.class.getName()}; } } // importingClassMetadata 就是能获取这个类的所有注解信息,Configuration、PropertySource、ComponentScan 等 @Configuration @PropertySource("classpath:jdbc.properties") @ComponentScan("com.study") @Import(MyImportSelector.class) @EnableAspectJAutoProxy @EnableTransacTionManagement public class SpringConfig { public static void main(String[] args) { AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SpringConfig.class); User bean = app.getBean(User.class); System.out.println(bean); } }
-
导入实现了 ImportBeanDefinitionRegistrar 的类
// 一个实现了 ImportBeanDefinitionRegistrar 接口的类 public class MyBeanDefinitionRegister implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 创建一个 BeanDefinition AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition(); // 注册到 ioc 容器 registry.registerBeanDefinition("user", beanDefinition); } } @Configuration @Import(User.class) @Import(MyBeanDefinitionRegister.class) public class SpringConfig { public static void main(String[] args) { AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SpringConfig.class); User bean = app.getBean(User.class); System.out.println(bean); } }
这个很容易装逼,显得代码很高级(springboot也有这样用的)举个简单的例子
// 定义一个注解,导入 MyBeanDefinitionRegister @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Import(MyBeanDefinitionRegister.class) public @interface CyrusScan{ } // 定义 MyBeanDefinitionRegister public class MyBeanDefinitionRegister implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition(); registry.registerBeanDefinition("user", beanDefinition); } } // 启动类或配置类使用自定义注解 CyrusScan,就会自动注册 User 类型的 bean @Configuration @CyrusScan public class SpringConfig { }
-
-
@EnableAspectJAutoProxy
- 开启自动代理
- 对应 xml 标签
<aop:aspectj-autoproxy/>
-
@EnableTransacTionManagement
-
开启事务自动代理,也就是声明式事物管理
-
对应 xml 标签
<tx:annotation-driven transaction-manager="transactionManager"/>
-