Spring框架之bean的作用范围及生命周期的注解

Spring框架之bean的作用范围及生命周期的注解

Bean的作用范围注解  
	* 注解为@Scope(value="prototype"),作用在类上。值如下:
		* singleton		-- 单例,默认值
		* prototype		-- 多例
Bean的生命周期的配置(了解)作用在方法上
	* 注解如下:
		* @PostConstruct	-- 相当于init-method
		* @PreDestroy		-- 相当于destroy-method
		
		例如:
		@PostConstruct
		public void init(){
			System.out.println("serivce初始化方法执行了");
		}

案例演示

  1. 创建maven项目,在pom.xml中引入所需的依赖

    <dependencies>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <scope>compile</scope>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.7</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    

2,创建一张account表

create table account(
	id int primary key auto_increment,
	name varchar(40),
	money float
)character set utf8 collate utf8_general_ci;

insert into account(name,money) values('aaa',1000);
insert into account(name,money) values('bbb',1000);
insert into account(name,money) values('ccc',1000);

3.开始分包创建相应的类

在com.itheima.bean包中创建Account实体类 Account.class

  public class Account implements Serializable {
    private Integer id;
    private String name;
    private Float money;
    //get set 方法略,自己补上
}

4.在service包中创建接口IAccountService,提供crud的方法

public interface IAccountService {
    List<Account> findAll();//查询所有
    Account findAccountByID(Integer id);//根据id查询一个
    void saveAccount(Account account);//保存
    void updateAccount(Account account);//更新
    void deleteAccountByID(Integer id);//根据id删除
}
  1. 写一个该接口的实现类IAccountServiceImpl,然后具体去实现crud的操作

  2. 在Dao包中创建IAccountDao 接口

     public interface IAccountDao {
        List<Account> findAll();//查询所有
    
        Account findAccountByID(Integer id);//根据id查询一个
    
        void saveAccount(Account account);//保存
    
        void updateAccount(Account account);//更新
    
        void deleteAccountByID(Integer id);//根据id删除
    }
    
    

7.创建IAccountDao接口的实现类 IAccountDaoImpl

8.在IAccountServiceImpl中提供 IAccountDao dao 并提供set方法

 public class IAccountServiceImpl implements IAccountService {
    
    IAccountDao dao;

    public void setDao(IAccountDao dao) {
        this.dao = dao;
    }
    //其他方法 略
}
  1. 在IAccountServiceImpl 中的方法中,调用dao中的方法
此处只展示一个
 public List<Account> findAll() {
        List<Account> list = dao.findAll();
        return list;
    }

10.在IAccountDaoImpl中提供 QueryRunner 的引用并提供set方法 使用他来完成crud操作,因为queryRunner只能采用构造方法的办法来提供注入依赖

QueryRunner queryRunner;

    public QueryRunner getQueryRunner() {
        return queryRunner;
    }

    public void setQueryRunner(QueryRunner queryRunner) {
        this.queryRunner = queryRunner;
    }
 public List<Account> findAll() throws SQLException {
       // System.out.println(queryRunner);
        List<Account> list = queryRunner.query("select * from account", new BeanListHandler<Account>(Account.class));
        return list;

    }

11.在resources目录下 创建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 http://www.springframework.org/schema/context/spring-context.xsd">
   <!--配置数据源-->
    <bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
        <!--配置四个属性值-->
        <property name="user" value="root"/>
        <property name="password" value="123456"/>
        <property name="jdbcUrl" value="jdbc:mysql:///spring_test"/>
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    </bean>
    <!--配置QueryRunner-->
    <bean class="org.apache.commons.dbutils.QueryRunner" id="queryRunner">
<!--注入数据源,只能采用构造的方法注入-->
        <constructor-arg name="ds" ref="dataSource"/>
    </bean>
    <!--配置Dao-->
    <bean class="com.itheima.dao.IAccountDaoImpl" id="accountDao">
        <property name="queryRunner" ref="queryRunner"/>
    </bean>
    <!--配置service-->
    <bean class="com.itheima.service.IAccountServiceImpl" id="accountService">
    <!--注入Dao-->
        <property name="accountDao" ref="accountDao"/>
    </bean>


</beans>

13.编写测试类,测试我们的crud 操作

public class MyTest {
    @Test
    public void testFindAll() throws SQLException {
        //读取配置文件
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContect.xml");
       // Object accountService = context.getBean("accountService");
        IAccountService accountService = context.getBean("accountService", IAccountService.class);
        List<Account> list = accountService.findAll();
        for (Account account : list) {
            System.out.println(account);
        }


    }
}

开始使用注解的方式对上面的案例进行改造
  1. 使用注解的时候需要新的约束
<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">
</beans> 

2.使用注解需要开启注解扫描

 <!--使用注解需要开启注解扫描-->
  <context:component-scan base-package="com.itheima">
  </context:component-scan>

3.可以删除 dao和service的配置 只留下下面的

 <!--使用注解需要开启注解扫描-->
  <context:component-scan base-package="com.itheima">
  </context:component-scan>
   <!--配置数据源-->
    <bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
        <!--配置四个属性值-->
        <property name="user" value="root"/>
        <property name="password" value="123456"/>
        <property name="jdbcUrl" value="jdbc:mysql:///spring_test"/>
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    </bean>
    <!--配置QueryRunner 配置成多例的-->
    <bean class="org.apache.commons.dbutils.QueryRunner" id="queryRunner" scope="prototype">
<!--注入数据源,只能采用构造的方法注入-->
        <constructor-arg name="ds" ref="dataSource"/>
    </bean>

4.在dao和service 上添加注解 并注入要使用的对象

@Repository(value = "accountDao")
public class IAccountDaoImpl implements IAccountDao {
    @Autowired  //自动注入 采用注解注入set方法可以省略不写
    QueryRunner queryRunner;  
    ...
  }
  
@Service(value = "accountService")
public class IAccountServiceImpl implements IAccountService {
    @Autowired  //注入dao
    IAccountDao dao;
    ...
}  

5.测试

使用Spring的新注解,完全替代applicationContext.xml中的配置
  1. 在com.itheima.config 包下新创建一个类 SpringConfig这个类就相当于要替代applicationContext.xml 这个配置文件。

  2. 在这个SpringConfig类上添加一个新的注解 @Configuration代表这是一个配置类

    @Configuration
    public class SpringConfig {
    
    }
    
  3. 我们再想办法把applicationContext.xml配置文件中的那行注解扫描,也使用注解的方式替代掉
    <context:component-scan base-package=“org.westos”></context:component-scan>
    怎么替代上面这行注解扫描呢?
    我们可以使用一个新的注解@ComponentScan 表示通过此注解指定spring在容器时要扫描的包
    @ComponentScan(basePackages = “org.westos”)
    @ComponentScan(value = “org.westos”)
    这里ComponentScan注解的属性 value和basePackages 意思是一样的,使用哪个都行
    例子:

    
    @Configuration
    @ComponentScan(value = "com.itheima")//注解扫描
    public class SpringConfig {
    }
    
  4. 我们接下来再想办法,把applicationContext.xml中的下面这个配置,也想办法替换掉

    <bean class="org.apache.commons.dbutils.QueryRunner" id="queryRunner" scope="prototype">
               <!--注入数据源,只能使用构造方法注入-->
               <constructor-arg name="ds" ref="dataSource"></constructor-arg>
           </bean>
    
    
    

    也就是把创建 QueryRunner对象的操作使用注解替换掉

    我们在SpringConfig这个配置类中,提供一个方法,方法的返回值,就是返回一个QueryRunner对象

    如果我们仅仅只是提供了这么一个方法,方法返回一个QueryRunner对象,但是这个对象并没有放到spring容器中
    所以我们还得在方法上使用一个注解 @Bean 表示把这个方法返回的这个对象,放到spring容器中
    @Bean 这个注解有一个属性 name 表示用于指定bean的id,如果不写默认的值是当前方法的名称也就是 name的默认值是createQueryRunner 这个方法名


@Configuration
@ComponentScan(value = "com.itheima")//注解扫描
public class SpringConfig {
    @Bean(name = "queryRunner")
   public QueryRunner createQueryRunner(DataSource dataSource){

       return new QueryRunner(dataSource);//new 一个QueryRunner对象返回
   }

5.我们采用同样的方式,替换掉applicationContext.xml中数据源的配置

​ 我们在SpringConfig这个配置类中,提供一个方法,方法的返回值是一个数据源对象

 @Bean(value = "dataSource")//把返回的数据源对象,放到spring容器中
    public DataSource createComboPooledDataSource() throws PropertyVetoException {
        ComboPooledDataSource ds = new ComboPooledDataSource();
        ds.setDriverClass("com.mysql.jdbc.Driver");
        ds.setJdbcUrl("jdbc:mysql:///spring_test");
        ds.setUser("root");
        ds.setPassword("123456");
        return ds;
    }

6.上面的操作做完之后,我们 applicationContext.xml 中配置的内容就可以删了

  1. 我们可以把applicationContext.xml这个配置文件删了,但是删了,我们要使用
    AnnotationConfigApplicationContex 这个类,来加载我们的SpringConfig这个类中的注解配置.
  2. 测试
@Test
    public void testFindAll() throws SQLException {
       //传入我们配置类的字节码对象
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        //获取dao对象
        IAccountDao dao = context.getBean("accountDao", IAccountDao.class);
        List<Account> list = dao.findAll();
        for (Account account : list) {
            System.out.println(account);
        }

9.代码优化

创建数据源的时候发现四个基本参数是写死的,我们可以将参数抽离到一个配置文件中,那么我们在resources目录下创建一个jdbcConfig.properties 配置文件,内容如下

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_test
jdbc.username=root
jdbc.password=123456

10.我们也可以设置多个配置类比如把SpringConfig这个类设置为一个主配置类,他里面比如可以设置一些公共的配置,然后我们在创建一个配置类比如 JDBCConfig这个配置类,然后我们把主配置类里面的配置拿到JDBCConfig这个配置类当中 如下

public class JDBCConfig {
    @Bean(name = "queryRunner")
    @Scope(value = "prototype") //配置成多例的
    public QueryRunner createQueryRunner(DataSource dataSource) {
        return new QueryRunner(dataSource);
    }

    @Bean(name = "dataSource")
    public DataSource createComboPooledDataSource() throws PropertyVetoException {
        ComboPooledDataSource ds = new ComboPooledDataSource();
        ds.setDriverClass("com.mysql.jdbc.Driver");
        ds.setJdbcUrl("jdbc:mysql:///spring_test");
        ds.setUser("root");
        ds.setPassword("123456");
        return ds;
    }
}

那么这时候我们主配置类中没有了配置
@Configuration
@ComponentScan(basePackages = "ocom.itheima")
public class SpringConfig {

}
我们的测试代码,是加载的主配置类
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); //传入我们配置类的字节码对象
所以我们应该在主配置类中导入子配置类,怎么导入?使用一个 @Import(value = JDBCConfig.class) 的注解
注意该注解的value属性要的是一个 .class 类型,不是字符串类型
@Configuration
@ComponentScan(basePackages = "com.itheima")
@Import(value = JDBCConfig.class) //导入子配置类的字节码对象
public class SpringConfig {

}

然后我们再在JDBCConfig类中提供四个成员变量
然后在成员变量上面使用@Value注解来读取jdbcConfig.properties中的配置
然后在创建数据源的方法中直接使用四个成员变量
如下:

public class JDBCConfig {
 	//注意这里的键的名称要和jdbcConfig.properties文件中的键名保持一致
    @Value(value = "${jdbc.driver}")
    private String driverClass;
    @Value(value = "${jdbc.url}")
    private String jdbcUrl;
    @Value(value = "${jdbc.username}")
    private String user;
    @Value(value = "${jdbc.password}")
    private String password;
    @Bean(name = "queryRunner")
    @Scope(value = "prototype") //配置成多例的
    public QueryRunner createQueryRunner(DataSource dataSource) {
        return new QueryRunner(dataSource);
    }
     @Bean(name = "dataSource")
    public DataSource createComboPooledDataSource() throws PropertyVetoException {
        ComboPooledDataSource ds = new ComboPooledDataSource();
        //使用成员变量的值
        ds.setDriverClass(driverClass);
        ds.setJdbcUrl(jdbcUrl);
        ds.setUser(user);
        ds.setPassword(password);
        return ds;
    }
}

可以使用一个注解 @PropertySource 来读取

@PropertySource(value = "classpath:jdbcConfig.properties")
代码如下:
@Configuration
@ComponentScan(basePackages = "com.itheima")
@Import(value = JDBCConfig.class) //导入子配置类的字节码对象
@PropertySource(value = "classpath:jdbcConfig.properties") //读取类路径下的配置文件
public class SpringConfig {

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值