码迷,mamicode.com
首页 > 其他好文 > 详细

三、常用IOC注解

时间:2020-09-12 21:45:53      阅读:27      评论:0      收藏:0      [点我收藏+]

标签:string   org   特点   lap   instance   png   el表达式   匿名   字节   

1.创建对象,依赖注入,作用范围,生命周期

前言:曾经的xml配置

<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl" scope=""
    init-method="" destroy-method="" >
	<property name="" value=""></property> 
   <property name="" ref=""></property>
</bean>
  1. 用于创建对象的:他们的作用 就和在XML配置文件中编写一个<bean>标签实现的功能是一样的

    • component :
      • 作用:用于把当前类对象存入spring容器中
      • 属性:
        • value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。
    • Controller:一般用在表现层
    • Service:一般用在业务层
    • Repository:一般用在持久层
    • Controller,Service,Responsitory三个注解的作用和属性与Component是一 模一 样。
      他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰
  2. 用于注入数据的:
    他们的作用就和在xml配置文件中的bean标签中写一个<property>标签的作用是一样的

    • Autowired:

      • 作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
      • 出现位置:
        可以是变量上,也可以是方法上
      • 细节:
        在使用注解注入时,set方法就不是必须的了。

      技术图片

    • Qualifier:

      • 作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以单独使用。
      • 属性:
        • value:用于指定注入bean的id。

      技术图片

      @Service("accountService")
      public class AccountServiceImpl implements IAccountService {
          @Autowired
          @Qualifier("accountDao1")//用于指定注入类中的具体的名称,若没有这个注解,
                                  // 变量名accountDao只能写成accountDao1或accountDao2
          private IAccountDao accountDao = null;
          @Override
          public void saveAccount() {
              accountDao.saveAccount();
          }
      }
      
      @Repository("accountDao1")
      public class AccountDaoImpl implements IAccountDao {
          @Override
          public void saveAccount() {
              System.out.println("保存成功!");
          }
      }
      
      @Repository("accountDao2")
      public class AccountDaoImpl1 implements IAccountDao {
          @Override
          public void saveAccount() {
              System.out.println("保存成功!");
          }
      }
      
      
    • Resource
      :

      • 作用:直接按照bean的id注入。它可以独立使用
      • 属性:
        • name:用于指定bean的Id
      @Service("accountService")
      public class AccountServiceImpl implements IAccountService {
          @Resource(name="accountDao1")//和上面那种写法所实现的功能一致,只是,这个可以单独使用,上面的得配套使用
          private IAccountDao accountDao = null;
          @Override
          public void saveAccount() {
              accountDao.saveAccount();
          }
      }
      

      以上三个注入都只能往入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
      另外,集合类型的注入只能通过XML来实现。

    • Value:

      • 作用:用于注入基本类型和String类型的数据
      • 属性:
        value:用于指定数据的值。它可以使用spring中SpEL (也就是spring的el表达式
        )
        • SpEL的写法: ${表达式}
      public class JdbcConfig {
          
          @Value("${driverClass}")
          String driverClass;
          @Value("${jdbcUrl}")
          String jdbcUrl;
          @Value("${user}")
          String user;
          @Value("${password}")
          String password;
          @Bean("dataSource")
          public DataSource createDataSource(){
              ComboPooledDataSource ds = new ComboPooledDataSource();
              try {
                  ds.setDriverClass(driverClass);
                  ds.setJdbcUrl(jdbcUrl);
                  ds.setUser(user);
                  ds.setPassword(password);
      
              } catch (PropertyVetoException e) {
                  e.printStackTrace();
              }
              return ds;
          }
      }
      
      
  3. 用于改变作用范围的:他们的作用就和在bean标签中使用scope属性实现的功能是一样的

    • Scope

      • 作用:用于指定bean的作用范围
      • 属性:
        • value:指定范围的取值。
        • 常用取值: singleton prototype
  4. 和生命周期相关:
    他们的作用就和在bean标签中使用init-method和destroy-method的作用是一样的

    • PreDestroy:
      • 作用:用于指定销毁方法
    • PostConstruct:
      • 作用:用于指定初始化方法
    package com.itheima.service.impl;
    
    import com.itheima.dao.IAccountDao;
    import com.itheima.service.IAccountService;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    import javax.annotation.Resource;
    
    /**
     * @author TearCheer
     * @create 2020-05-25-16:29
     */
    @Service("accountService")
    @Scope("prototype")
    public class AccountServiceImpl implements IAccountService {
    //    @Autowired
    //    @Qualifier("accountDao1")//用于指定注入类中的具体的名称,若没有这个注解,
    //                            // 变量名accountDao只能写成accountDao1或accountDao2
        @Resource(name="accountDao1")//和上面两个注解所实现的功能一致,只是,这个可以单独使用,上面得配套使用
        private IAccountDao accountDao = null;
        @PostConstruct
        public void init(){
            System.out.println("对象初始化了!");
        }
        @PreDestroy
        public void destroy(){
            System.out.println("对象销毁了!");
        }
    
        @Override
        public void saveAccount() {
            accountDao.saveAccount();
        }
    
    }
    

2.基于account表的案例摘要

  1. spring中的新注解

    • Configuration:

      • 作用:指定当前类是一个配置类

      • 细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。

      • 当有多个配置类时,而在用AnnotationConfigApplicationContext创建对象时,参数中只传入了一个配置类的字节码,则在被传入的那个配置类上得声明其它配置类的位置

        以下是测试类

      package com.itheima.service;
      
      import com.itheima.domain.Account;
      import config.JDBCConfig;
      import config.SpringConfiguration;
      import org.junit.Test;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      import java.util.List;
      
      /**
       * @author TearCheer
       * @create 2020-05-29-11:51
       */
      public class AccountServiceImplTest {
          AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);//只传入了SpringConfiguration的class属性
          @Test
          public void testFindAllAccount(){
              IAccountService serviceAccount = ac.getBean("accountService", IAccountService.class);
              List<Account> allAccount = serviceAccount.findAllAccount();
              allAccount.forEach(System.out::println);
          }
      }
      

      以下是两个配置类:

      package config;
      
      import com.mchange.v2.c3p0.ComboPooledDataSource;
      import org.apache.commons.dbutils.QueryRunner;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      
      import javax.sql.DataSource;
      import java.beans.PropertyVetoException;
      
      /**
       * @author TearCheer
       * @create 2020-05-29-18:24
       */
      
      @Configuration
      public class JdbcConfig {
          /**
           * @Description:  用于创建一个QueryRunner对象
           * @date: 2020/5/29 17:04
           * @return:
           */
          @Bean(name = "runner")
          public QueryRunner createQueryRunner(DataSource dataSource){
              return new QueryRunner(dataSource);
          }
          @Bean("dataSource")
          public DataSource createDataSource(){
              ComboPooledDataSource ds = new ComboPooledDataSource();
              try {
                  ds.setDriverClass("com.mysql.cj.jdbc.Driver");
                  ds.setJdbcUrl("jdbc:mysql:///mydb?useSSL=false&serverTimezone=UTC");
                  ds.setUser("root");
                  ds.setPassword("a123");
      
              } catch (PropertyVetoException e) {
                  e.printStackTrace();
              }
              return ds;
          }
      }
      
      

      作为传入参数的配置类

      package config;
      import org.springframework.context.annotation.ComponentScan;
      
      /**
       * @author TearCheer
       * @create 2020-05-29-16:52
       */
      //@Configuration
      //@ComponentScan({"com.itheima", "config"})此时,JdbcConfig配置类中要声明@Configuration
      @ComponentScan("com.itheima")
      @Import(JdbcConfig.class)//此时,JdbcConfig配置类中不用声明@Configuration
      public class SpringConfiguration {
      
      }
      
      
    • ComponentScan:

      • 作用:用于通过注解指定spring在创建容器时要扫描的包

      • 属性:

        • value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包

        • 我们使用此注解就等同于在xml中配置了:

          <context:component-scan base-package="com.itheima"/>

    • Bean

      • 作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中
      • 属性:
        • name:用于指定bean的id。当不写时,默认值是当前方法名称。
        • 细节:当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象,查找方法和Autowired注解的作用是一样的
      package config;
      //improt...
      /**
       * @author TearCheer
       * @create 2020-05-29-18:24
       */
      
      //@Configuration
      public class JdbcConfig {
          /**
           * @Description:  用于创建一个QueryRunner对象
           * @date: 2020/5/29 17:04
           * @return:
           */
          @Bean(name = "runner")
          @Scope("prototype")//声明作用范围为:多例
          public QueryRunner createQueryRunner(DataSource dataSource){
              return new QueryRunner(dataSource);
          }
          @Bean(name = "dataSource")
          public DataSource createDataSource(){
              ComboPooledDataSource ds = new ComboPooledDataSource();
              return ds;
          }
      }
      
      
    • Import

      • 作用:用于导人其他的配置类
      • 属性:
        • value:用于指定其他配置类的字节码。
        • 当我们使用Import的注解之后,有Import注解的类就父配置类,而导入的都是子配置类
    • PropertySource

      • 作用:用于指定properties文件的位置
      • 属性:
        • value:指定文件的名称和路径。
        • 关键字: classpath, 表示类路径下
      package config;
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Import;
      import org.springframework.context.annotation.PropertySource;
      
      /**
       * @author TearCheer
       * @create 2020-05-29-16:52
       */
      @ComponentScan("com.itheima")
      @Import(JdbcConfig.class)@Configuration
      @PropertySource("classpath:jdbcConfig.properties")//指定properties文件的位置
      public class SpringConfiguration {
      
      }
      
      
  2. Spring整合Junit的配置

    技术图片

    • 导入spring整合的Junit的jar(坐标)
    • 使用Junit提供一个注解把原有的main方法替换了,替换成spring提供的
      • 用@Runwith来设置
    • 告知spring的运行器,spring和ioc的创建是基于xml还是注解的,并且说明位置
      • 用ContextConfiguration设置
        • locations:指定xml文件的位置,加上classpath关键字,表示在该类路径下
        • classes:指定注解类所在的位置
    • 当我们使用spring5.x版本时,要求Junit的jar必须是4.12及以上
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = SpringConfiguration.class)
    public class AccountServicImplSpringTest {
        @Autowired
        IAccountService serviceAccount = null;
        @Test
        public void testFindAllAccount(){
            List<Account> allAccount = serviceAccount.findAllAccount();
            allAccount.forEach(System.out::println);
        }
       //...
    }
    

3.补充:动态代理

  1. 特点:字节码随用随创建,随用随加载

  2. 作用:不修改源码的基础上对方法增强

  3. 分类:

    • 基于接口的动态代理
    • 基于子类的动态代理
  4. 基于接口的动态代理:

    • 涉及的类: Proxy
    • 提供者: JDK官方
  5. 如何创建代理对象:

    • 使用Proxy类中的newProxyInstance方法
  6. 创建代理对象的要求:

    • 被代理类至少实现一个接口,如果没有则不能使用

    • newProxyInstance方法的参数:

      • ClassLoader:类加载器

        • 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。写法固定。
      • Class[]:字节码数组

        • 它是用于让代理对象和被代理对象有相同的方法。写法固定。
      • InvocationHandler:用于提供增强的代码

        • 它是让我们写如何代理。我们一般都是实现一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
        • 此接口的实现类都是谁用谁写
      public class Client {
          public static void main(String[] args) {
              Producer producer = new Producer();
      
              IProducer iProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
                      producer.getClass().getInterfaces(),
                      new InvocationHandler() {
                          @Override
                          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                              /**
                               * @Description: 执行被代理对象的任何接口方法都会经过该方法
                               * 方法参数的含义:
                               * proxy 代理对象的引用
                               * method 当前执行的方法
                               * args  当前执行方法所需要的参数
                               * @date: 2020/5/30 21:17
                               * @return: java.lang.Object  和被代理对象有相同的返回值
                               */
                              //提供增强代码
                              Object returnValue = null;
                              //1.获取当前执行方法的参数
                              Float money = (Float) args[0];
                              //2.判断当前方法是不是销售
                              if ("saleProduct".equals(method.getName())) {
                                  returnValue = method.invoke(producer, (float) (money * 0.8));
                              }
                              return returnValue;
                          }
                      });
              iProducer.saleProduct(1000f);
          }
      }
      
      
  7. 基于子类的动态代理:

    • 涉及的类:Enhancer
    • 提供者:第三方cglib库
  8. 如何创建代理对象:

    • 使用Enhancer类中的create方法
  9. 创建代理对象的要求

    • 被代理类不能是最终类
  10. create方法的参数:

    • Class:字节码
      • 它是用于指定被代理对象的字节码。
    • Callback:用于提供增强的代码
      • 它是让我们写如何代理。我们一般都是实现一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
      • 我们一般写的都是该接口的子接口实现类:MethodInterceptor
    public class Client {
        public static void main(String[] args) {
            Producer producer = new Producer();
            Producer producer1 = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    /**
                     * @Description: 执行被代理对象的任何方法都会经过该方法
                     * 方法参数:
                     * o 代理对象的引用
                     * method 当前执行的方法
                     * objects   当前执行方法所需要的参数
                     * methodProxy  当前执行方法的代理对象
                     * @date: 2020/5/30 21:49
                     * @return: java.lang.Object
                     */
                    //提供增强代码
                    Object returnValue = null;
                    //1.获取当前执行方法的参数
                    Float money = (Float) objects[0];
                    //2.判断当前方法是不是销售
                    if ("saleProduct".equals(method.getName())) {
                        returnValue = method.invoke(producer, (float) (money * 0.8));
                    }
                    return returnValue;
                }
            });
            producer1.saleProduct(1000f);
        }
    
    }
    

三、常用IOC注解

标签:string   org   特点   lap   instance   png   el表达式   匿名   字节   

原文地址:https://www.cnblogs.com/TearCheer/p/13592697.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!