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

  1. 要是用 @Bean 标注某个方法,这个方法的返回值就是真实 bean,可以指定名称,如果不指定默认是方法名
  2. 方法所在的类要被 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{

}
  1. @Configuration

    1. 标注当前的 bean 是一个配置 bean,代替 spring 上下文的配置文件
    2. 对应 xml 标签 <context:annotation-config/>
  2. @PropertySource

    1. 读取 properties 文件
    2. 对应 xml 标签 <context:property-placeholder location = "classpath:jdbc.properties" />
  3. @ComponentScan

    1. 自动扫描包
    2. 对应 xml 标签 <context:component-scan base-package="com.example"/>
  4. @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 {
          
      }
      
      
  5. @EnableAspectJAutoProxy

    1. 开启自动代理
    2. 对应 xml 标签 <aop:aspectj-autoproxy/>
  6. @EnableTransacTionManagement

    1. 开启事务自动代理,也就是声明式事物管理

    2. 对应 xml 标签 <tx:annotation-driven transaction-manager="transactionManager"/>

posted @ 2024-06-29 16:42  CyrusHuang  阅读(3)  评论(0编辑  收藏  举报