• Spring系统学习--1、IOC和DI


    Spring,Spring,Spring,天天用,但是对她太过缺乏“深入”的了解,今天思虑良久,下定决心,我要好好“深入的”了解一下她。

    Spring是一个架构性的框架:也就是改变代码结构的框架;

    1.学习环境的准备

    大部分教学视频是使用老掉牙Ecliplse教学Spring的,但是我TM是真的不想用Ecliplse,虽然我电脑上有Ecliplse...如果你要选择Ecliplse那么你可以跟着视频老老实实创建java项目--->导入jar包--->创建XML配置文件,完成spring学习环境的搭建;但是下面我要说的是我是如何使用IDEA开始Spring的学习的:

     

     创建完maven项目之后,在pom.xml文件里面添加如下依赖:
    <!--  spring-context:导入spring核心jar包  -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>5.0.7.RELEASE</version>
    <!--      <scope>test</scope>-->
        </dependency>
    <!--    导入日志jar包-->
        <dependency>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
          <version>1.2</version>
        </dependency>
      </dependencies>

    然后,你会发现项目依赖库下面增加了许多spring相关jar:

    然后我们在项目资源文件夹src下面创建spring的配置文件:

     这样你就可以愉快的开始spring学习之旅了....简单吧

    2.IOC入门案例

    2.1在bean.xml里面添加如下配置:

    前提是下面的类已经在对应的路径下创建了:

    <!--
    bean:来映射一个类
    id:是bean的唯一标识,如果没有指定则默认将会以类名作为标识
    class:映射类的全路径
    IOC容器管理默认是单例
    -->
    <bean id="accountService" class="main.java.service.impl.IAccountServiceImpl"></bean>
    <bean id="accountDao" class="main.java.dao.impl.IAccountDaoImpl"></bean>

     2.2获取Spring的核心容器,并且根据bean的id获取对象

    创建一个类,书写如下代码:

    public class Client {
        public static void main(String[] args) {
            /**
             * 获取Spring的核心容器,并且根据bean的id获取对象
             *
             * ApplicationContext:是BeanFactory的孙子接口,创建对象的时候采取的是立即加载的策略.(读取完XML配置文件之后,xml里面所有的bean对象就已经全部创建完成了)
             */
    //        1.获取容器
            ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
    //        2.根据bean的id获取对象
            IAccountService iAccountService=(IAccountService)context.getBean("accountService");
            IAccountDao accountDao = context.getBean("accountDao", IAccountDao.class);
            System.out.println(iAccountService);
            System.out.println(accountDao);
        }
    }

    补充:ApplicationContext子类:

           /* * ApplicationContext子类:
             * -----ClassPathXmlApplicationContext:
             *      她是通过读取类路径下的配置文件创建spring容器;要求配置文件在类路径下
             * -----FileSystemXmlApplicationContext
             *      她是通过读取文件系统中的配置文件创建spring容器;要求配置文件在文件系统中即可
             */

    2.3懒加载

    如果我ლxml文件里面bean非常多,在创建容器的时候我们瞬间初始化那么多bean可能会导致卡顿,这个时候我们可以在xml文件里面按照下图:就能实现在调用getBean时才初始化:

     2.4懒加载容器

    如果我们不想通过上面的配置实现懒加载,下面的代码也可以实现在getBean时才创建对象:

    public class Client {
        public static void main(String[] args) {
            /**
             * 获取Spring的核心容器,并且根据bean的id获取对象
             *
             * ApplicationContext:是BeanFactory的孙子接口,创建对象的时候采取的是理解加载的策略.(读取完XML配置文件之后,xml里面所有的bean对象就已经全部创建完成了)
             * BeanFactory:是springIoc的顶层接口,创建bean对象时,采用延迟加载的策略(当真正要从容器中获取对象时,才会创建,读完配置文件并不创建)
             */
    //        1.获取容器
            ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
    //        2.获取对象
            IAccountService iAccountService = (IAccountService) context.getBean("accountService");
            IAccountDao accountDao = context.getBean("accountDao", IAccountDao.class);
            System.out.println(iAccountService);
            System.out.println(accountDao);
    
    //        1.加载配置文件
            Resource resource = new ClassPathResource("bean.xml");
    //        2.获取容器
            BeanFactory beanFactory = new XmlBeanFactory(resource);
    //        3.获取对象
            IAccountService accountService = beanFactory.getBean("accountService", IAccountService.class);
        }
    }

    2.5bean对象的三种创建方式

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
    ><!--default-lazy-init="true" :设置所有的bean为懒加载 -->
    
    <!--spring管理bean对象细节:
    bean标签:来映射一个类
        作用:让spring帮我们读取配置之后创建对象
        属性:
            id:是bean的唯一标识,如果没有指定则默认将会以类名作为标识
            class:映射类的全路径
            factory-method:指定创建bean对象的方法;
            factory-bean:指定创建bean对象的工厂bean的id
    
    bean对象的三种创建方式:
                        1.通过调用默认构造函数创建bean对象   (常用)
                        在默认情况下我们在spring配置文件中写了一个bean标签,并提供了class属性,spring就会调用默认构造方法创建对象
                        2.通过静态工厂创建bean对象
                            工厂类中提供一个静态方法,可以返回一个我们要获取的类的对象
                            public class BeanFactory {
                                    public static IAccountService getBean1() {
                                        return new IAccountServiceImpl();
                                     }
                                                      }
                        3.通过实例工厂创建bean对象
                             工厂类中提供一个非静态方法,可以返回一个我们要获取的类的对象
                             public class BeanFactory {
                                     public IAccountService getBean2() {
                                             return new IAccountServiceImpl();
                                     }
                                                       }
    -->
    <!--    1.默认方式创建对象:-->
    <bean id="accountService" class="main.java.service.impl.IAccountServiceImpl"></bean>
    <!--    2.静态工厂创建对象
                            id:bean的id
                            class:工厂类
                            factory-method:工厂类里面生成bean对象的方法(静态方法)
    -->
        <bean id="staticFactory" class="main.java.factory.BeanFactory" factory-method="getBean1"></bean>
    
    <!--    3.实例工厂创建对象
                            factory-bean:指定工厂bean的id
                            factory-method:指定工厂类里面生产bean对象的方法(非静态方法)
    -->
        <bean id="instanceFactory" class="main.java.factory.BeanFactory"></bean>
        <bean id="instanceFactoryBean" factory-bean="instanceFactory" factory-method="getBean2"></bean>
    </beans>
    public class CreatBeanTest {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
    //        1.默认构造函数创建对象,获取方法
            IAccountService accountService = context.getBean("accountService", IAccountService.class);
            System.out.println(accountService);//main.java.service.impl.IAccountServiceImpl@17f7cd29
    //        2.静态工厂创建对象,获取方法
            IAccountService accountService1 = context.getBean("staticFactory", IAccountService.class);
            System.out.println(accountService1);//main.java.service.impl.IAccountServiceImpl@7d8704ef
    //        3.实例工厂创建对象,获取方法
            IAccountService accountService2 = context.getBean("instanceFactoryBean", IAccountService.class);
            System.out.println(accountService2);//main.java.service.impl.IAccountServiceImpl@17f7cd29
        }
    }

    2.6bean对象的作用范围:

    <!--
    bean对象的作用范围:
        它是可以通过配置的方式来指定的。
        配置的属性:bean标签的scope属性
        属性的取值:
            singleton:单例的。默认值
            prototype:多例的.
            request:WEB项目中,Spring创建一个Bean的对象,将对象存入到 request域中。
            session:WEB项目中,Spring创建一个Bean的对象,将对象存入到 session域中。
            global-session:WEB项目中,应用在 Portlet环境,如果没有Portlet环境那么 global-session相当于session
    
    -->
    <bean id="accountService" class="main.java.service.impl.IAccountServiceImpl" scope="prototype"></bean>

    2.7bean对象的生命周期:

    <!--
    bean对象的生命周期:
        单例对象
            出生:容器创建对象出生
            活着:只要容器存在,对象就一直可用。
            死亡:容器销毁,对象消亡。
        多例对象
            出生:每次使用时,容器会为我们创建对象。
            活着:只要对象在使用过程中,就一直活着。
            死亡:当对象长时间不用,并且也没有其他对象引用时,由java的垃圾回收器回收.
    -->
    <bean id="singleton_accountService" class="main.java.service.impl.IAccountServiceImpl" scope="singleton" init-method="init" destroy-method="destory"></bean>
    <bean id="prototype_accountService" class="main.java.service.impl.IAccountServiceImpl" scope="prototype" init-method="init" destroy-method="destory"></bean>
    public class IAccountServiceImpl  implements IAccountService {
        IAccountDao iAccountDao=new IAccountDaoImpl();
        public IAccountServiceImpl(){
            System.out.println("对象创建了!!!");
        }
        public void init(){
            System.out.println("对象初始化了");
        }
        public void destory(){
            System.out.println("对象销毁了了");
        }
        @Override
        public void saveAccount() {
            iAccountDao.save();
        }
    }
    public class _05LifecycleTest {
        public static void main(String[] args) {
    //        1.获取容器
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean_lifecycle.xml");
    //        2.获取对象
            IAccountService accountService1 = context.getBean("singleton_accountService", IAccountService.class);
            System.out.println(accountService1);
            IAccountService accountService2 = context.getBean("prototype_accountService", IAccountService.class);
            System.out.println(accountService2);
    //        3.销毁容器
            context.close();
        }
    }

    3.DI依赖注入

    3.1介绍两种注入类型

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!--
    Spring的依赖注入
        注入的方式:只有3中(今天只涉及两种)
                    第一种方式:通过构造函数注入
                    第二种方式:通过set方法注入
        注入的内容:
                    第一类:基本类型和String类型
                    第二类:其他的bean类型
                    第三类:复杂类型(集合类型)
    -->
    <!--
    第一种:使用构造函数注入:
                该方式要求对应的类必须有对应的带参构造方法
                涉及的标签:
                constructor-arg
                该标签是写在bean标签内部的子标签
                标签的属性:
                    type:指定要注入的参数在构造函数中的类型
                    index:指定要注入的参数在构造函数的索引位置
                    name:指定参数在构造函数的中的名称
                    value:指定注入的数据内容,他只能指定基本类型数据和String类型数据
                    ref:指定其他bean类型数据。写的是其他bean的id。其他bean指的是存在于spring容器中的bean。
    -->
    <!--    1.构造方法注入-->
    <bean id="accountService" class="main.java.service.impl.IAccountServiceImpl" >
        <constructor-arg name="name" value="李沁"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
        <constructor-arg name="birthday" ref="birthday"></constructor-arg>
    </bean>
    <bean id="birthday" class="java.util.Date"></bean>
    <!--
    第二种:使用set方法注入常用
                涉及的标签:
                property
                该标签也是要写在bean标签内部的子标签
                标签的属性:
                    name:指定的是set方法的名称。匹配的是类中set后面的部分的全小写。
                    value:指定注入的数据内容,他只能指定基本类型数据和String类型数据
                    ref:指定其他bean类型数据。写的是其他bean的id。其他bean指的是存在于spring容器中的bean。
    -->
    <!--    2.set方法注入-->
        <bean id="accountService2" class="main.java.service.impl.IAccountServiceImpl" >
            <property name="name" value="李沁2"></property>
            <property name="age" value="17"></property>
            <property name="birthday" ref="birthday"></property>
        </bean>
    </beans>
    public class IAccountServiceImpl  implements IAccountService {
        private String name;
        private int age;
        private Date birthday;
    
        public IAccountServiceImpl(String name, int age, Date birthday) {
            this.name = name;
            this.age = age;
            this.birthday = birthday;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public IAccountServiceImpl(){
            System.out.println("对象创建了!!!");
        }
        @Override
        public void saveAccount() {
            System.out.println(name+age+birthday);
        }
    }
    public class _06DI {
        public static void main(String[] args) {
    //        1.获取容器
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean_DI.xml");
    //        2.获取对象
            IAccountService accountService1 = context.getBean("accountService", IAccountService.class);
            accountService1.saveAccount();
            IAccountService accountService2 = context.getBean("accountService2", IAccountService.class);
            accountService2.saveAccount();
    //        3.销毁容器
            context.close();
        }
    }

    3.2  P名称空间注入:

    <!--
    使用p名称空间注入
        它的本质仍然是需要类中提供set方法,同时在配置文件中要导入p名称空间
    -->
        <bean id="accountService3" class="main.java.service.impl.IAccountServiceImpl" p:name="李沁3">
        </bean>

     3.3特殊类型属性注入

    public class CollectionsDI {
        private String [] strings;
        private List<String>myList;
        private Set<String> mySet;
        private Map<String,String>myMap;
        private Properties myProps;
    
        public void setStrings(String[] strings) {
            this.strings = strings;
        }
    
        public void setMyList(List<String> myList) {
            this.myList = myList;
        }
    
        public void setMySet(Set<String> mySet) {
            this.mySet = mySet;
        }
    
        public void setMyMap(Map<String, String> myMap) {
            this.myMap = myMap;
        }
    
        public void setMyProps(Properties myProps) {
            this.myProps = myProps;
        }
        public void print(){
            System.out.println(Arrays.toString(strings));
            System.out.println(myList);
            System.out.println(myMap);
            System.out.println(mySet);
            System.out.println(myProps);
        }
    }
    <bean id="CollectionsDI" class="main.java.service.CollectionsDI" >
            <!-- 1.给数组注入数据-->
            <property name="strings">
                <array>
                    <value>args</value>
                    <value>args</value>
                    <value>args</value>
                </array>
            </property>
            <!-- 2.给List注入数据-->
            <property name="myList">
                <list>
                    <value>LIST</value>
                    <value>LIST</value>
                    <value>LIST</value>
                </list>
            </property>
            <!-- 3.给Set注入数据-->
            <property name="mySet">
                <set>
                    <value>SET</value>
                    <value>SET</value>
                    <value>SET</value>
                </set>
            </property>
            <!-- 4.给Map注入数据-->
            <property name="myMap">
                <map>
                    <entry key="001" value="map"></entry>
                    <entry key="002">
                        <value>map注入方式2</value>
                    </entry>
                </map>
            </property>
            <!-- 5.给Properties注入数据-->
            <property name="myProps">
                <props>
                    <prop key="url">http:www.baidu.com</prop>
                </props>
            </property>
        </bean>
    public class _06DI {
        public static void main(String[] args) {
    //        1.获取容器
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean_DI.xml");
    //        2.获取对象
            CollectionsDI collectionsdi = context.getBean("CollectionsDI", CollectionsDI.class);
            collectionsdi.print();
            /**
             [args, args, args]
             [LIST, LIST, LIST]
             {001=map, 002=map注入方式2}
             [SET1, SET2, SET3]
             {url=http:www.baidu.com}
             */
    //        3.销毁容器
            context.close();
        }
    }

    注意:上面xml文件里面bean标签内部结构相同的标签可以互换使用:

     <!-- 1.给数组注入数据-->
            <property name="strings">
                <list>
                    <value>LIST</value>
                    <value>LIST</value>
                    <value>LIST</value>
                </list>
            </property>
            <!-- 2.给List注入数据-->
            <property name="myList">
                <array>
                    <value>args</value>
                    <value>args</value>
                    <value>args</value>
                </array>
            </property>    

    3.4注入时特殊符号处理

     3.5注解注入

      一,用于创建对象的注解:

    /***
     * 账号业务层实现类
     * 原来在XML的配置
     * <bean id="IAccountService_annotation" class="main.java.service.impl.IAccountService_annotationImpl" >
     *     <property name="iAccountDao_annotation" ref="dao"></property>
     * </bean>
     * 上面原来在XML里面的配置现在可以使用下面的注解搞定:
     *  注解的分类
     *     一,用于创建对象的:
     *          @Component:
     *          作用:就相当于在spring的xml配置文件中写了一个bean标签。
     *          属性:
     *              value:用于指定bean的id。当不写时,默认值是当前类名,首字母改小写。例如:accountServiceImpl
     *      由此注解衍生的三个注解:
     *                @Controller:一般用于表现层
     *                @Service:一般用于业务层
     *                @Repository:一般用于持久层
     *                他们的作用以及属性和@Component的作用是一模一样的。他们的出现是spring框架为我们提供更明确的语义化来指定不同层的bean对象。
    */
    //@Component(value = "IAccountService_annotation")
    //@Service(value = "IAccountService_annotation")
    @Repository(value = "IAccountService_annotation")
    public class IAccountService_annotationImpl implements IAccountService_annotation {
    ...
    }

    上面的代码就实现了将类IAccountService_annotationImpl 交给Spring容器作为组件管理,当然,前提是上面这个类要在Spring启动的时候被Spring扫描到,配置Spring的扫描路径是在spring的xml配置文件里添加如下代码:

    <!--告知Spring创建容器时要扫描的包:这些包下面所有带有Spring注解的内容都会被加载到Spring容器里面-->
        <context:component-scan base-package="main.java.service"></context:component-scan>
        <context:component-scan base-package="main.java.dao"></context:component-scan>

      二,用于注入数据的:

    /**
     *     二,用于注入数据的:
     *           @Autowired
     *           作用:自动按照类型注入。只要容器中有唯一的类型匹配,则可以直接注入成功。如果没有匹配的类型就报错。
     *                如果有多个类型匹配时,会先按照类型找到符合条件的对象,然后再用变量名称作为bean的id,从里面继续查找,如果找到仍然可以注入成功,如果没有匹配的id,就报错
     *           细节:当使用此注解注入时,set方法就可以省略了。
     *           属性:
     *               required:是否必须注入成功。取值是true(默认值)/false。当取值是true时,没有匹配的对象就报错。
     *           @Qualifier作用:在自动按照类型(@Autowired)注入的基础之上,再按照bean的id注入。在给类成员注入时,它不能够浊立使用。
     *           属性:
     *              value:用于指定bean的id。
     *           @Resource作用:直接按照bean的id注入。
     *           属性:
     *              name:用于指定bean的id。
     *          以上3个注解,都只能用于注入其他bean类型,而不能注入基本类型和String。
     *          用于注入基本类型和String类型的注解
    */
    //@Component(value = "IAccountService_annotation")
    //@Service(value = "IAccountService_annotation")
    @Repository(value = "IAccountService_annotation")
    public class IAccountService_annotationImpl implements IAccountService_annotation {
      //@Autowired
      //@Qualifier(value = "dao")
        @Resource(name = "dao")
        private IAccountDao_annotation iAccountDao_annotation;
    
     /*   public void setiAccountDao_annotation(IAccountDao_annotation iAccountDao_annotation) {
            this.iAccountDao_annotation = iAccountDao_annotation;
        }*/
    
        @Override
        public void saveAccount() {
            iAccountDao_annotation.save();
        }
    }

      @Value:

    /**
               @Value作用:用于注入基本类型和String类型的数据。
               属性:
                    value:用于指定要注入的数据。它支持使用spring的el表达式。
                    spring的el表达式写法:
                                        ${表达式}
    **/
    
    @Repository(value = "IAccountService_annotation")
    public class IAccountService_annotationImpl implements IAccountService_annotation {
        @Value("https://www.hao123.com/")
        public String url;
        @Value("${jdbc.driver}")
        private String driver;
     @Override
        public void saveAccount() {
            System.out.println(url);//https://www.hao123.com/
            System.out.println(driver);//com.mysql.jdbc.Driver;
            iAccountDao_annotation.save();
        }
    }
    spring的el表达式的使用前提是:
    1.我们要提前创建了相应的配置文件:

     2.我们在spring的xml配置文件里面添加如下注解:

    <!--    告知Spring,properties配置文件的位置-->
        <context:property-placeholder location="dataBaseConfig.properties"></context:property-placeholder>

      三,用于改变作用范围:

    /**
           三,用于改变作用范围:
     *      @Scope
     *          作用:用于改变bean的作用范围。范围的取值和xml中的配置是一样的(单例:singleton;多例:prototype)
     *          属性:
     *              value:用于指定范围。
    **/
    @Component(value = "IAccountService_annotation")
    @Scope("prototype")//多例(默认情况是单例)
    public class IAccountService_annotationImpl implements IAccountService_annotation {
    ...
    }

    测试代码:

        public static void main(String[] args) {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean_annotation.xml");
            IAccountService_annotation annotation = context.getBean("IAccountService_annotation", IAccountService_annotation.class);
            IAccountService_annotation annotation2 = context.getBean("IAccountService_annotation", IAccountService_annotation.class);
            System.out.println(annotation==annotation2);//false
    }

      四,和生命周期相关的:

    /**
     *      四,和生命周期相关的:
     *          @PostContruct
     *              作用:用于指定初始化方法。和配置文件中init-method属性是一样的
     *          @PreDestroy
     *              作用:用于指定销毁方法。和配置文件中destroy-method属性是一样的
     */
    @Component(value = "IAccountService_annotation")
    @Scope("singleton")
    public class IAccountService_annotationImpl implements IAccountService_annotation {
        @PostConstruct
        public void init(){
            System.out.println("对象初始化了");
        }
        @PreDestroy
        public void destory(){
            System.out.println("对象销毁了");
        }
    }

      补充内容:

        @Autowired图解

         @Resource爆红?

     Alt+Enter

     

     最后项目pom.xml会添加上如下内容,并在对应jar下载完毕之后,就可以使用@Resource了:

        <dependency>
          <groupId>jakarta.annotation</groupId>
          <artifactId>jakarta.annotation-api</artifactId>
          <version>1.3.4</version>
        </dependency>

    注意属性如果只有一个value要赋值,那么value可以省略@Component(value = "IAccountService")可以写作@Component("IAccountService")
  • 相关阅读:
    jquery 年月日分离
    Jquery实现常用的分类搜索跳转
    SQL Server 利用触发器对多表视图进行更新
    TEA XTEA XXTEA 学习笔记
    IDApro自带动调初探
    HECTFreverse部分writeup
    NCTF2021逆向WP(部分)
    buuctf[刮开有奖]writeup
    base64学习笔记
    深夜写文——致19岁的自己
  • 原文地址:https://www.cnblogs.com/luzhanshi/p/11685763.html
Copyright © 2020-2023  润新知