zoukankan      html  css  js  c++  java
  • 基于注解的 IOC 配置

    基于注解的 IoC 配置,和XML要实现的功能都是一样的,都是要降低程序之间的耦合,只是配置的形式不一样。
    1、环境搭建: 建立maven工程,导入所需的maven坐标:
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.mingqi</groupId>
        <artifactId>springAnnoioc</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.0.2.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>commons-dbutils</groupId>
                <artifactId>commons-dbutils</artifactId>
                <version>1.4</version>
            </dependency>
    
            <dependency>
                <groupId>com.microsoft.sqlserver</groupId>
                <artifactId>sqljdbc4</artifactId>
                <version>4.0</version>
            </dependency>
    
            <dependency>
                <groupId>c3p0</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.1.2</version>
            </dependency>
    
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.10</version>
            </dependency>
        </dependencies>
    
    </project>

    2、使用@Component 注解配置管理的资源

    /**
    * 账户的业务层实现类
    */
    @Component("accountService")
    public class AccountServiceImpl implements IAccountService {
    private IAccountDao accountDao;
    public void setAccountDao(IAccountDao accountDao) {
    this.accountDao = accountDao; } }
    /**
    * 账户的持久层实现类
    */
    @Component("accountDao")
    public class AccountDaoImpl implements IAccountDao {
    private DBAssit dbAssit; }
    注意:
     当我们使用注解注入时,set 方法不用写
    3、创建 spring 的 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">
        <!-- 告知spring在创建容器时要扫描的包 -->
        <context:component-scan base-package="com.mingqi"></context:component-scan>
        <!--配置QueryRunner-->
        <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
            <!--注入数据源-->
            <constructor-arg name="ds" ref="dataSource"></constructor-arg>
        </bean>
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
            <property name="jdbcUrl" value="jdbc:sqlserver://localhost:1433;DatabaseName=test"/>
            <property name="user" value="sa"/>
            <property name="password" value="123sa"/>
        </bean>
        <bean id="usersDao" class="com.mingqi.dao.impl.UsersDaoimpl">
            <property name="runner" ref="runner"></property>
        </bean>
        <bean id="usersService" class="com.mingqi.service.impl.UsersServiceImpl">
            <property name="usersDao" ref="usersDao"></property>
        </bean>
    </beans>

    4、常用注解

    (1)用于创建对象的  相当于:<bean id="" class="">

           ① @Component   

                作用:把资源让 spring 来管理。相当于在 xml 中配置一个 bean。

                属性:value:指定 bean 的 id。如果不指定 value 属性,默认 bean 的 id 是当前类的类名。首字母小写。

            ② @Controller @Service @Repository 他们三个注解都是针对一个的衍生注解,他们的作用及属性都是一模一样的。他们只不过是提供了更加明确的语义化。

                @Controller:一般用于表现层的注解。
                @Service:一般用于业务层的注解。
                @Repository:一般用于持久层的注解。
                细节:如果注解中有且只有一个属性要赋值时,且名称是 value,value 在赋值是可以不写
    (2)用于注入数据的 相当于:<property name="" ref=""> <property name="" value="">
          ① @Autowired 自动按照类型注入。当使用注解注入属性时,set 方法可以省略。它只能注入其他 bean 类型。当有多个类型匹配时,使用要注入的对象变量名称作为 bean 的 id,在 spring 容器查找,找到 了也可以注入成功。找不到就报错。
          ②@Qualifier
             作用:在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。它在给字段注入时不能独立使用,必须和@Autowire 一起使用;但是给方法参数注入时,可以独立使用。
             属性:value:指定 bean 的 id
          ③@Resource
           作用:直接按照Bean的Id注入,他也只能注入其bean类型
           属性: name:指定bean的id
          ④@Value
           作用:注入基本数据类型和String数据类型
           属性:value:用于指定值
    (3)用于改变作用范围的 相当于:<bean id="" class="" scop="">
       @Scope 作用:用于指定bean的作用范围   
        属性: value:指定范围的值:  取值:singleton(单例) prototype(多例)  request session  globalsession
     (4)和声明周期相关的
          ①@PostConstruct  作用:用于指定初始化方法
          ②@PreDestroy      作用:用于指定销毁方法
    (5)关于 Spring 注解和 XML 的选择问题
    注解的优势:
    配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。
    XML 的优势:
    修改时,不用改源码。不涉及重新编译和部署。
    Spring 管理 Bean 方式的比较:

    基于注解的 spring IoC 配置中,bean 对象的特点和基于 XML 配置是一模一样的,但是还是需要spring的xml配置文件,name能不能不写这个bean.xml,所有的配置都用注解来实现呢?

    (6)新注解说明

          ①@Configuration 作用:用于指定当前类是一个 spring 配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration 注解的类.class)。

           属性:value:用于指定配置类的字节码
           
    /*
     spring 的配置类,相当于 bean.xml 文件
     */
    @Configuration
    public class SpringConfig {
    }
    我们已经把配置文件用类来代替了,但是如何配置创建容器时要扫描的包呢?
    请看下一个注解。
          ②@ComponentScan 作用:用于指定 spring 在初始化容器时要扫描的包。作用和在 spring 的 xml 配置文件中的:<context:component-scan base-package="com.itheima"/>是一样的。
            属性:basePackages:用于指定要扫描的包。和该注解中的 value 属性作用一样。 

        ③@Bean  作用:该注解只能写在方法上,表明使用此方法创建一个对象,并放入spring容器中

                       属性:name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)

           
    /*
     spring 的配置类,相当于 bean.xml 文件
     */
    @Configuration
    @ComponentScan("com.mingqi")
    public class SpringConfig {
    
        private DataSource dataSource;
        private QueryRunner runner;
    
        /**
         * 注入dataSource
         * @return
         */
        @Bean(name="dataSource")
        public ComboPooledDataSource createDataSource() {
            try {
                ComboPooledDataSource ds = new ComboPooledDataSource();
                ds.setUser("sa");
                ds.setPassword("123sa");
                ds.setDriverClass("com.microsoft.sqlserver.jdbc.SQLServerDriver");
                ds.setJdbcUrl("jdbc:sqlserver://localhost:1433;DatabaseName=test");
                return ds;
            } catch (Exception e) {
                throw new RuntimeException(e);
            } }
    
        /**
         * 创建一个QueryRunner 并放入bean容器中
         * @param dataSource
         * @return
         */
        @Bean(name="runner")
        public QueryRunner runner(DataSource dataSource) {
            //this.dataSource = dataSource;
            return new QueryRunner(dataSource);
        }
    }
    我们已经把数据源和 QueryRunner从配置文件中移除了,此时可以删除 bean.xml 了。
    但是由于没有了配置文件,创建数据源的配置又都写死在类中了。下面我们将它们从类中拿出来
     
    ④ @PropertySource  作用:加载.properties文件中的配置,例如我们配置数据源时,可以把链接数据库的信息写到properties配置文件中,就可以使用此注解指定properties配置文件的位置
       属性:value[] 指定properties文件位置,如果是在类路径下,需要写上classpath
    public class JdbcConfig {
        @Value("${jdbc.driver}")
        private String driver;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.password}")
        private String password;
        @Bean(name="dataSource")
        public DataSource createDataSource() {
            try {
                ComboPooledDataSource ds = new ComboPooledDataSource();
                ds.setDriverClass(driver);
                ds.setJdbcUrl(url);
                ds.setUser(username);
                ds.setPassword(password);
                return ds;
            } catch (Exception e) {
                throw new RuntimeException(e);
            } }
    }

    properties 文件内容:

    jdbc.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
    jdbc.url=jdbc:sqlserver://localhost:1433;DatabaseName=test
    jdbc.username=sa
    jdbc.password=123sa
    此时我们已经有了两个配置类,但是他们还没有关系。如何建立他们的关系呢?
    ⑤ @Import 作用:用于导入其他配置类,在引入其他配置类时,可以不再写@Configuration注解,当然写上也没有什么问题
                  属性:value[] 用于指定其他配置类的字节码
    @Configuration
    @PropertySource("classpath:com/mingqi/config/jdbc.properties")
    public class JdbcConfig {
    }
    
    @Configuration
    @ComponentScan("com.mingqi")
    @Import({ JdbcConfig.class})
    public class SpringConfig {
    }

     (6) 通过注解获取容器:

            ApplicationContext ac =new AnnotationConfigApplicationContext(SpringConfiguration.class); 

    (7) 在测试类中,每个测试方法都有以下两行代码:

    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");

    IAccountService as = ac.getBean("accountService",IAccountService.class);

    这两行代码的作用是获取容器,如果不写的话,直接会提示空指针异常。所以又不能轻易删掉。 

    针对上述问题,我们需要的是程序能自动帮我们创建容器。一旦程序能自动为我们创建 spring 容器,我们就无须手动创建了,问题也就解决了。

    junit 是无法实现的,因为它自己都无法知晓我们是否使用了 spring 框架,更不用说帮我们创建 spring 容器了。不过好在,junit 给我们暴露了一个注解,可以让我们替换掉它的运行器。这时,我们需要依靠 spring 框架,因为它提供了一个运行器,可以读取配置文件(或注解)来创建容器。我们只需要告诉它配置文件在哪就行了。
       ①第一步:拷贝整合 junit 的必备 jar 包到 lib 目录  此处需要注意的是,导入 jar 包时,需要导入一个 spring 中 aop 的 jar 包。
       ②使用@RunWith 注解替换原有运行器 
         @RunWith(SpringJUnit4ClassRunner.class)
    public class AccountServiceTest {
    } 
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations= {"classpath:bean.xml"})
    public class AccountServiceTest {
    }
    /*
    @ContextConfiguration 注解:
    locations 属性:用于指定配置文件的位置。如果是类路径下,需要用 classpath:表明
    classes 属性:用于指定注解的类。当不使用 xml 配置时,需要用此属性指定注解类的位置。
    */

      ③ 使用@Autowired 给测试类中的变量注入数据

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations= {"classpath:bean.xml"})
    public class AccountServiceTest {
    @Autowired
    private IAccountService as ; }
    为什么不把测试类配到 xml 中 ?
    在解释这个问题之前,先解除大家的疑虑,配到 XML 中能不能用呢?
    答案是肯定的,没问题,可以使用。
    那么为什么不采用配置到 xml 中的方式呢?
    这个原因是这样的:
    第一:当我们在 xml 中配置了一个 bean,spring 加载配置文件创建容器时,就会创建对象。
    第二:测试类只是我们在测试功能时使用,而在项目中它并不参与程序逻辑,也不会解决需求上的问
    题,所以创建完了,并没有使用。那么存在容器中就会造成资源的浪费。
    所以,基于以上两点,我们不应该把测试配置到 xml 文件中。
  • 相关阅读:
    微信小程序上传文件(报错处理方式)
    自绘 TreeDataView 控件
    C# 读取outlook 本地签名
    【英雄帖】FreeRedis 邀请您一起优化项目。
    (30)ASP.NET Core3.1 集成Apollo快速安装与使用
    C#引用fo-dicom读取dicom文件异常
    .NET 开源导入导出库 Magicodes.IE 2.5发布
    WinUI 3 Preview 3 发布了,再一次试试它的性能
    Aspose.Word for DotNet 定位到每页,画笔 移动到某页。
    .NET Core下好用的FTP框架 FluentFTP
  • 原文地址:https://www.cnblogs.com/mingqi-420/p/13055859.html
Copyright © 2011-2022 走看看