Spring学习笔记01

目录

一、HelloWorld

Spring是什么?

具体描述Spring

Spring模块

二、IOC&DI概述

IOC的前生

三、配置 Bean

1、第一步:

2、第二步:

3、第三步:

四、属性配置细节

 五、自动装配

六、Bean之间的关系

七、Bean的作用域

八、使用外部属性文件

九、SpEL

十、管理 Bean 的生命周期

十一、通过工厂方法配置 Bean

十二、通过 FactoryBean 配置 Bean

十三、通过注解配置 Bean(1)

十四、通过注解配置 Bean(2)

十五、泛型依赖注入


一、HelloWorld

Spring是一个框架

Spring官网:稳定版是 spring6.0.8


 

现在很多框架的下载推荐使用maven的方式

Spring是什么?

1、Spring是一个开源框架,是可以看见源代码的,Spring的源代码非常优秀

2、Spring是为简化企业级应用开发而生,比如使用声明式事务非常轻松,以前需要繁琐的配置,复杂的代码才能够实现

3、Spring是一个IOC(DI)和 AOP 容器框架,最核心的两个功能

      IOC:反转控制    DI:依赖注入

具体描述Spring

轻量级Spring是非侵入性的-基于Spring开发的应用中的对象可以不依赖于Spring的API

spring是轻量级的,并不是说jar包有多大,主要是说spring是非侵入性的
我们用spring的时候,不需要实现spring给我们提供的任何接口,不需要去继承它的任何父类,然后我们就可以用spring给我们提供的功能,有点润物细无声的那种感觉

依赖注入(DI---dependency injection、IOC)

面向切面编程(AOP---aspect oriented programming)

容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期

框架:Spring实现了使用简单的组件配置组合成一个复杂的应用,在Spring中可以使用XML和Java注解组合这些对象

一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架(整合MyBatis等等)和优秀的第三方类库(实际上 Spring自身也提供了展现层的 SpringMVC 和持久层的 Spring JDBC)

Spring模块

最底层是核心容器

Beans:在核心容器里面可以配置bean

Context:上下文

SpEL:Spring的EL表达式

AOP、Aspect:面向切面编程

声明式事务,整合mybatis

Imstrumentation:整合
Messaging:消息

web模块可以用到Spring提供的springmvc,可以整合其他框架

==============================================

HelloWorld 测试

第一步:新建项目,导入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.nanjing</groupId>
    <artifactId>spring-1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.0.0.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.0.0.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.0.0.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.0.0.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

    </dependencies>
</project>

第二步:新建HelloWorld.java文件

public class HelloWorld {

    private String name;

    public void setName(String name) {
        System.out.println("setName: " + name);
        this.name = name;
    }

    public void hello(){
        System.out.println("hello: "+name);
    }

    /**
     * 在Java中的每个类都至少有一个构造方法,如果在一个类中没有定义构造方法,系统会自动为这个类创建一个默认的构造方法
     * 这个默认的构造方法没有参数,在其方法体中没有任何代码,即什么也不做
     */
    public HelloWorld() {
        System.out.println("HelloWorld's Constructor...");
    }
}

第三步:新建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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 配置bean
         class:bean的全类名,通过反射的方式在IOC容器中创建bean,所以要求Bean中必须有无参的构造器
         id:标识容器中的bean,id唯一
    -->
    <bean id="helloWorld" class="com.nanjing.spring.bean.HelloWorld">
        <property name="name" value="江苏大剧院"></property>
    </bean>
</beans>

第四步:新建Main.java文件

public class Main {
    public static void main(String[] args) {

        /**
        // 创建HelloWorld的一个对象
        HelloWorld helloWorld = new HelloWorld();
        //为name 属性赋值
        helloWorld.setName("nanjing");
        */

        //1、创建spring的IOC容器对象
        //在创建容器的时候,它会调用构造器对我在配置文件里面配置的那个bean进行初始化,同时会调用set方法对那个属性进行赋值
        ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");

        //2、从IOC容器中获取Bean实例
        HelloWorld helloWorld=(HelloWorld) ctx.getBean("helloWorld");

        //3、调用hello 方法
        helloWorld.hello();
    }
}

二、IOC&DI概述

IOC(Inversion of Control):其思想是反转资源获取的方向。传统的资源查找方式要求组件向容器发起请求查找资源,作为回应,容器适时的返回资源。

而应用了IOC之后,则是容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源,这种行为也被称为查找的被动形式

DI(Dependency Injection)-- IOC的另一种表述方式:即组件以一些预定义好的方式(例如:setter方法)接受来自如容器的资源注入,相对于IOC而言,这种方式更直接

通俗点讲:

以前买菜,需要到菜市场买,现在只要在院子里放一个小框,菜就会自动的给到你,反转资源获取的方向

实例讲解

传统的方式如右上案例

IOC容器如右下案例:B与A之间建立一种关联关系,容器自动的把关联关系建立好了,通过set方法把A对象的引用赋值给B的成员变量a

IOC的前生

我有一个需求,这个接口是ReportGenerator(报表生成器)会生成两种方式,一种是pdf,另一种是html方式

现在我有一个报表服务类ReportService需要用到这个报表生成器,有可能用到的是pdf方式,有可能html方式

service需要画出三条线,既需要知道这个接口类型,也需要知道你具体有哪些实现类,有可能我还需要知道如何创建实现类的对象,这种是耦合度最高的一种方式

我们需要知道这个接口和实现类的具体细节

原始时代,需要一把斧子,不但需要知道斧子的形状,还需要知道手工地打一把斧子,这个要求是很高的

在封建社会,我需要一把斧子,可以去铁匠铺,给他银子,做一把斧子,这个时候耦合度就降低了,service层只需要画出两条线,一条线是我肯定需要知道接口类型
,同时需要指向这个工厂就行了,这个工厂负责帮我生成这个接口的实现类,代码复杂了,分工更加明确了,项目容易扩展,更加灵活

按需分配,我需要什么东西,政府就会把我需要材料给我,service只需要画出一条线,由容器把我需要的接口的实现类直接注入给我就行了
反转资源的控制方向

三、配置 Bean

1、第一步:

 <!-- 配置bean
         class:bean的全类名,通过反射的方式在IOC容器中创建bean,所以要求Bean中必须有无参的构造器
         id:标识容器中的bean,id唯一
    -->
    <!-- 全类名应该是用反射的方式由spring帮我们创建这么一个对象 id是标识这个对象的,需要一个无参构造器
    name对应的应该是set方法,用setter来定义的javabean这一风格的属性名-->
    <bean id="helloWorld" class="com.nanjing.spring.bean.HelloWorld">
        <property name="name" value="江苏大剧院"></property>
    </bean>

2、第二步:

//1、创建spring的IOC容器对象
        //ApplicationContext代表的就是spring里面的IOC容器,这是一个接口
        //ClassPathXmlApplicationContext代表的是配置文件在类路径下,是ApplicationContext的一个实现类

        //在创建容器的时候,它会调用构造器对我在配置文件里面配置的那个bean进行初始化,同时会调用set方法对那个属性进行赋值
        ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");

3、第三步:

//2、从IOC容器中获取Bean实例
        //利用id定位到IOC容器中的bean
        HelloWorld helloWorld=(HelloWorld) ctx.getBean("helloWorld");
        //利用类型返回IOC容器中的Bean,但要求IOC容器中必须只能有一个该类型的Bean
        //HelloWorld helloWorld=(HelloWorld) ctx.getBean("helloWorld");
        System.out.println(helloWorld);

4、第四步:

<!-- 配置bean
         class:bean的全类名,通过反射的方式在IOC容器中创建bean,所以要求Bean中必须有无参的构造器
         id:标识容器中的bean,id唯一
    -->
    <!-- 全类名应该是用反射的方式由spring帮我们创建这么一个对象 id是标识这个对象的,需要一个无参构造器
    name对应的应该是set方法,用setter来定义的javabean这一风格的属性名-->
    <bean id="helloWorld" class="com.nanjing.spring.bean.HelloWorld">
        <property name="name" value="江苏大剧院"></property>
    </bean>

    <!--通过构造方法来配置bean的属性-->
    <!--如何区分重载的方法-->
    <bean id="car" class="com.nanjing.spring.bean.Car">
        <constructor-arg value="Audi" index="0"></constructor-arg>
        <constructor-arg value="ShangHai" index="1"></constructor-arg>
        <constructor-arg value="300000" type="double"></constructor-arg>
    </bean>

    <!--使用构造器注入属性值可以指定参数的位置和参数的类型!以区分重载的构造器!-->
    <bean id="car2" class="com.nanjing.spring.bean.Car">
        <constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
        <!--如果字面值包含特殊字符可以使用<![CDATA[]]>包裹起来-->
        <!--属性值也可以使用value子节点进行设置-->
        <constructor-arg type="java.lang.String">
            <value><![CDATA[<Shanghai^>]]></value>
        </constructor-arg>
        <constructor-arg type="int">
            <value>250</value>
        </constructor-arg>
    </bean>

四、属性配置细节

applicationContext.xml很重要,精华

<!--使用构造器注入属性值可以指定参数的位置和参数的类型!以区分重载的构造器!-->
    <bean id="car2" class="com.nanjing.spring.bean.Car">
        <constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
        <!--如果字面值包含特殊字符可以使用<![CDATA[]]>包裹起来-->
        <!--属性值也可以使用value子节点进行设置-->
        <constructor-arg type="java.lang.String">
            <value><![CDATA[<Shanghai^>]]></value>
        </constructor-arg>
        <constructor-arg type="int">
            <value>250</value>
        </constructor-arg>
    </bean>

    <bean id="person" class="com.nanjing.spring.bean.Person">
        <property name="name" value="Tom"></property>
        <property name="age" value="24"></property>
        <!--可以使用property的ref属性建立bean之间的引用关系-->
<!--        <property name="car" ref="car2"></property>-->
        <!--内部bean,不能被外部引用,只能在内部使用-->
        <property name="car">
            <bean class="com.nanjing.spring.bean.Car">
                <constructor-arg value="Ford"></constructor-arg>
                <constructor-arg value="Changan"></constructor-arg>
                <constructor-arg value="240" type="int"></constructor-arg>
            </bean>
        </property>
    </bean>

    <bean id="person2" class="com.nanjing.spring.bean.Person">
        <constructor-arg value="Jerry"></constructor-arg>
        <constructor-arg value="25"></constructor-arg>
        <!--        <constructor-arg ref="car2"></constructor-arg>-->
        <!--测试赋值null-->
        <!--        <constructor-arg><null/></constructor-arg>-->
        <!--为级联属性赋值,注意:属性需要先初始化后才可以为级联属性赋值,否则会有异常,和struts2不同-->
        <constructor-arg ref="car"></constructor-arg>
        <property name="car.maxSpeed" value="240"></property>
    </bean>

    <!--测试如何配置集合属性-->
    <bean id="person3" class="com.nanjing.spring.bean.collections.Person">
        <property name="name" value="Mike"></property>
        <property name="age" value="27"></property>
        <property name="cars">
            <!--使用list节点为List类型的属性赋值-->
            <list>
                <ref bean="car"/>
                <ref bean="car2"/>
                <bean class="com.nanjing.spring.bean.Car">
                    <constructor-arg value="Ford"></constructor-arg>
                    <constructor-arg value="Changan"></constructor-arg>
                    <constructor-arg value="240" type="int"></constructor-arg>
                </bean>
            </list>
        </property>
    </bean>

    <!--配置Map属性值-->
    <bean id="newPerson" class="com.nanjing.spring.bean.collections.NewPerson">
        <property name="name" value="Rose"></property>
        <property name="age" value="28"></property>
        <property name="cars">
            <!--使用map节点及map的entry子节点配置Map类型的成员变量-->
            <map>
                <entry key="AA" value-ref="car"></entry>
                <entry key="BB" value-ref="car2"></entry>
            </map>
        </property>
    </bean>

    <!--配置Properties属性值-->
    <bean id="dataSource" class="com.nanjing.spring.bean.collections.DataSource">
        <property name="properties">
            <!--使用props和prop子节点来为Propertiess属性赋值-->
            <props>
                <prop key="user">root</prop>
                <prop key="password">123456</prop>
                <prop key="jdbcUrl">jdbc:mysql:///test</prop>
                <prop key="driverClass">com.mysql.jdbc.Driver</prop>
            </props>
        </property>
    </bean>

    <!--配置单例的集合bean,以供多个bean进行引用,需要导入util命名空间-->
    <util:list id="cars">
        <ref bean="car"/>
        <ref bean="car2"/>
    </util:list>

    <bean id="person4" class="com.nanjing.spring.bean.collections.Person">
        <property name="name" value="Jack"></property>
        <property name="age" value="28"></property>
        <property name="cars" ref="cars"></property>
    </bean>

    <!--通过p命名空间为bean的属性赋值,需要先导入p命名空间,相对于传统的配置方式更加的简洁-->
    <bean id="person5" class="com.nanjing.spring.bean.collections.Person" p:age="30"
          p:name="Queen" p:cars-ref="cars">
    </bean>

 五、自动装配(重点面试会问

beans-autowire.xml文件

<!--    <bean id="address2" class="com.nanjing.spring.beans.autowire.Address"-->
    <!--        p:city="BeiJing" p:street="HuiLongGuan"></bean>-->

    <bean id="address2" class="com.nanjing.spring.bean.autowire.Address"
          p:city="NanJing" p:street="ZhongShan"></bean>

    <bean id="car" class="com.nanjing.spring.bean.autowire.Car"
          p:brand="Audi" p:price="300000"></bean>

    <!--可以使用autowire属性指定自动装配的方式,
    byName 根据bean的名字和当前bean的setter 风格的属性名进行自动装配,若有匹配的,则进行自动装配,若没有匹配的,则不装配
    byType 根据bean的类型和当前bean的属性的类型进行自动装配,若IOC容器中有1个以上的类型匹配的bean,则抛异常
    -->
    <bean id="person" class="com.nanjing.spring.bean.autowire.Person"
          p:name="Tom" autowire="byType"></bean>

<!--        <bean id="person" class="com.nanjing.spring.bean.autowire.Person"-->
<!--            p:name="Tom" p:address-ref="address" p:car-ref="car"></bean>-->

六、Bean之间的关系

继承与依赖

beans-relation.xml文件

<!--抽象bean:bean的abstract属性为true的bean,这样的bean不能被IOC容器实例化,只用来被继承配置
   若某一个bean的class属性没有指定,则该bean必须是一个抽象bean-->
    <bean id="address" class="com.nanjing.spring.bean.autowire.Address"
          p:city="BeiJing^" p:street="WuDaoKou" abstract="true"></bean>

    <!--bean配置的继承:使用bean的parent属性指定继承哪个bean的配置-->
    <bean id="address2" class="com.nanjing.spring.bean.autowire.Address"
          p:city="BeiJing" p:street="DaZhongSi" parent="address"></bean>

    <bean id="car" class="com.nanjing.spring.bean.autowire.Car"
          p:brand="Audi" p:price="300000"></bean>

    <!--要求在配置Person时,必须有一个关联的car! 换句话说person这个bean 依赖于Car 这个 bean-->
    <bean id="person" class="com.nanjing.spring.bean.autowire.Person"
          p:name="Tom" p:address-ref="address2" depends-on="car"></bean>

七、Bean的作用域(面试会问

beans-scope.xml文件

<!--
    使用bean 的scope 属性来配置bean的作用域
    singleton:默认值,容器初始化时创建bean实例,在整个容器的生命周期内只创建这一个bean,单例的
    prototype:原型的,容器初始化时不创建bean的实例,而在每次请求时都创建一个新的bean实例,并返回
    -->
    <bean id="car" class="com.nanjing.spring.bean.autowire.Car" scope="prototype">
        <property name="brand" value="Audi"></property>
        <property name="price" value="300000"></property>
    </bean>

Main.java文件----测试

package com.nanjing.spring.bean.scope;

import com.nanjing.spring.bean.autowire.Car;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {

        ApplicationContext ctx=new ClassPathXmlApplicationContext("beans-scope.xml");

        Car car=(Car) ctx.getBean("car");
        Car car2=(Car) ctx.getBean("car");

        System.out.println(car == car2);
    }
}

八、使用外部属性文件

beans-properties.xml文件

 <!--导入属性文件-->
    <context:property-placeholder location="classpath:db.properties"/>

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--使用外部化属性文件的属性-->
        <property name="user" value="${user}"></property>
        <property name="password" value="${password}"></property>
        <property name="driverClass" value="${driverClass}"></property>
        <property name="jdbcUrl" value="${jdbcUrl}"></property>
    </bean>

db.properties文件

user=root
password=123456
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/test

Main.java文件

public class Main {
    public static void main(String[] args) throws SQLException {
        ApplicationContext ctx=new ClassPathXmlApplicationContext("beans-properties.xml");

        DataSource dataSource=(DataSource) ctx.getBean("dataSource");
        System.out.println(dataSource.getConnection());
    }
}

九、SpEL

十、管理 Bean 的生命周期

第一步:Car.java文件

public class Car {

    public Car() {
        System.out.println("Car's Constructor...");
    }

    private String brand;

    public void setBrand(String brand) {
        System.out.println("setBrand...");
        this.brand = brand;
    }

    public void init(){
        System.out.println("init...");
    }

    public void destroy(){
        System.out.println("destroy...");
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                '}';
    }
}

第二步:beans-cycle.xml文件

  <bean id="car" class="com.nanjing.spring.bean.cycle.Car"
          init-method="init" destroy-method="destroy">
        <property name="brand" value="Audi"></property>
    </bean>

第三步:Main.java文件

public class Main {
    public static void main(String[] args) {

        ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("beans-cycle.xml");

        Car car=(Car) ctx.getBean("car");
        System.out.println(car);

        //关闭IOC容器
        ctx.close();
    }
}

第四步:MyBeanPostProcessor.java文件

public class MyBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization: "+bean+", "+beanName);

        if("car".equals(beanName)){
            //...
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization: "+bean+", "+beanName);
        Car car=new Car();
        car.setBrand("Ford");
        return car;
    }
}

第五步:beans-cycle.xml文件

  <bean id="car" class="com.nanjing.spring.bean.cycle.Car"
          init-method="init" destroy-method="destroy">
        <property name="brand" value="Audi"></property>
    </bean>

    <!--
        实现BeanPostProcessor 接口,并具体提供
        Object postProcessBeforeInitialization(Object bean, String beanName):init-method 之前被调用
        Object postProcessAfterInitialization(Object bean, String beanName):init-method 之后被调用
        的实现

        bean:bean实例本身
        beanName: IOC容器配置的bean的名字

       返回值:是实际上返回给用户的那个Bean,注意:可以在以上两个方法中修改返回的bean,甚至返回一个新的bean
        -->
    <!--配置bean的后置处理器,不需要配置id,IOC 容器自动识别是一个BeanPostProcessor-->
    <bean class="com.nanjing.spring.bean.cycle.MyBeanPostProcessor"></bean>

十一、通过工厂方法配置 Bean

第一步:InstanceCarFactory.java文件

/**
 * 静态工厂方法:直接调用某一个类的静态方法就可以返回Bean的实例
 */
public class StaticCarFactory {

    //静态属性
    private static Map<String,Car> cars=new HashMap<String,Car>();

    static {
        cars.put("Audi",new Car("Audi",300000));
        cars.put("Ford",new Car("Ford",400000));
    }

    //静态工厂方法
    public static Car getCar(String name){
        return cars.get(name);
    }
}

第二步:beans-factory.xml文件

   <!--通过静态工厂方法来配置bean,注意不是配置静态工厂方法实例,而是配置bean实例-->
    <!--class属性:指向静态工厂方法的全类名
    factory-method:指向静态工厂方法的名字
    constructor-arg:如果工厂方法需要传入参数,则使用constructor-arg来配置参数
    -->
    <bean id="car1"
          class="com.nanjing.spring.bean.factory.StaticCarFactory" factory-method="getCar">
        <constructor-arg value="Audi"></constructor-arg>
    </bean>

第三步:测试类 Main.java文件

ApplicationContext ctx=new ClassPathXmlApplicationContext("beans-factory.xml");
Car car1=(Car) ctx.getBean("car1");
System.out.println(car1);

Car car2=(Car) ctx.getBean("car2");
System.out.println(car2);

第四步:InstanceCarFactory.java文件

/**
 * 实例工厂方法:实例工厂的方法,即现需要创建工厂本身,再调用工厂的实例方法来返回bean的实例
 */
public class InstanceCarFactory {

    private Map<String,Car> cars=null;

    public InstanceCarFactory() {
        cars=new HashMap<String, Car>();
        cars.put("Audi",new Car("Audi",300000));
        cars.put("Ford",new Car("Ford",400000));
    }

    public Car getCar(String brand){
        return cars.get(brand);
    }
}

第五步:

    <!--配置工厂的实例-->
    <bean id="carFactory" class="com.nanjing.spring.bean.factory.InstanceCarFactory"></bean>

    <!--通过实例工厂方法来配置bean-->
    <!--
    factory-bean 属性:指向实例工厂方法的bean
    factory-method: 指向实例工厂方法的名字
    constructor-arg:如果工厂方法需要传入参数,则使用constructor-arg来配置参数
    -->
    <bean id="car2" factory-bean="carFactory" factory-method="getCar">
        <constructor-arg value="Ford"></constructor-arg>
    </bean>

十二、通过 FactoryBean 配置 Bean

第一步:CarFactoryBean.java 文件

//自定义的FactoryBean 需要实现FactoryBean 接口
public class CarFactoryBean implements FactoryBean<Car> {

    private String brand;

    public void setBrand(String brand) {
        this.brand = brand;
    }

    //返回bean的对象
    public Car getObject() throws Exception {
        return new Car(brand,500000);
    }

    /**
     * 返回的bean的类型
     * @return
     */
    public Class<?> getObjectType() {
        return Car.class;
    }

    public boolean isSingleton() {
        return true;
    }
}

第二步:beans-factory.xml文件

<!--
       通过FactoryBean 来配置Bean的实例
       class:指向FactoryBean 的全类名
       property:配置FactoryBean的属性

       但实际返回的实例却是FactoryBean 的getObject()方法返回的实例!
   -->
    <bean id="car" class="com.nanjing.spring.bean.factorybean.CarFactoryBean">
        <property name="brand" value="BMW"></property>
    </bean>

十三、通过注解配置 Bean(1)

第一步:TestObject.java 文件

@Component
public class TestObject {

}

第二步:UserController.java文件

@Controller
public class UserController {

    public void execute(){
        System.out.println("UserController execute...");
    }
}

第三步:UserService.java文件

@Service
public class UserService {

    public void add(){
        System.out.println("UserService add...");
    }
}

第四步:UserRepository.java文件

public interface UserRepository {

    void save();
}

第五步:UserRepositoryImpl.java文件

@Repository("userRepository")
public class UserRepositoryImpl implements UserRepository{

    public void save() {
        System.out.println("UserRepository Save...");
    }
}

第六步:beans-annotation.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 IOC容器扫描的包-->
    <!--可以通过resource-pattern 指定扫描的资源-->
    <!--
    <context:component-scan
            base-package="com.nanjing.spring.bean.annotation"
            resource-pattern="repository/*.class"></context:component-scan>  -->

    <!-- context:exclude-filter 子节点指定排除哪些指定表达式的组件-->
    <!-- context:include-filter 子节点指定包含哪些表达式的组件,该子节点需要 use-default-filters 配合使用-->
    <context:component-scan
            base-package="com.nanjing.spring.bean.annotation">
        <!--
        <context:exclude-filter type="annotation"
                                expression="org.springframework.stereotype.Repository"/>
        -->
        <!--
        <context:include-filter type="annotation"
                                expression="org.springframework.stereotype.Repository"/>
        -->
        <!--
        <context:exclude-filter type="assignable"
                                expression="com.nanjing.spring.beans.annotation.repository.UserRepository"/>
        -->
        <!--        <context:include-filter type="assignable"-->
        <!--                                expression="com.nanjing.spring.beans.annotation.repository.UserRepository"/>-->
    </context:component-scan>

</beans>

第七步:Main.java文件

public class Main {
    public static void main(String[] args) {

        ApplicationContext ctx=new ClassPathXmlApplicationContext("beans-annotation.xml");

        TestObject to=(TestObject) ctx.getBean("testObject");
        System.out.println(to);

        UserController userController=(UserController) ctx.getBean("userController");
        System.out.println(userController);
        userController.execute();

        UserService userService=(UserService) ctx.getBean("userService");
        System.out.println(userService);

        UserRepository userRepository=(UserRepository) ctx.getBean("userRepository");
        System.out.println(userRepository);
    }
}

十四、通过注解配置 Bean(2)

 @Autowired
    private UserService userService;

如果IOC容器里面有好几个类型相匹配的Bean,怎么办?

第一种使用 @Qualifier

 @Autowired
    @Qualifier("userRepositoryImpl")
    private UserRepository userRepository;

第二种

@Repository("userRepository")
public class UserRepositoryImpl implements UserRepository{

十五、泛型依赖注入

泛型依赖注入(UML图)

两个基类BaseService带泛型的,BaseRpository带泛型的

BaseService和BaseRpository之间有一种引用关系,以便可以调用BaseRpository已经定义好的方法

我在BaserService里面有一个成员变量,是BaseRpository这种类型的,

BaseService可能会有很多实现类,BaseRpository可能会有很多实现类

UserService,在继承BaseService的时候,我需要提供这个泛型T,比如这个泛型T是User

UserService和UserRpository之间会自动的建立引用关系,这就是所谓的泛型依赖注入

=====================================

第一步:BaseService.java文件

public class BaseService<T> {

    @Autowired
    protected BaseRepository<T> repository;

    public void add(){
        System.out.println("add...");
        System.out.println(repository);
    }
}

第二步:BaseRepository.java文件

public class BaseRepository<T> {
}

第三步:UserService.java文件

@Service
public class UserService extends BaseService<User>{
}

第四步:UserRepository.java文件

@Repository
public class UserRepository extends BaseRepository<User>{
}

第五步:beans-generic-di.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">

    <context:component-scan base-package="com.nanjing.spring.bean.generic.di"></context:component-scan>
</beans>

第六步:Main.java文件

public class Main {
    public static void main(String[] args) {

        ApplicationContext ctx=new ClassPathXmlApplicationContext("beans-generic-di.xml");

        UserService userService=(UserService) ctx.getBean("userService");
        userService.add();
    }
}

输出结果:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring是一个开源的Java框架,用于构建企业级应用程序。它提供了一种轻量级的、非侵入式的开发方式,通过依赖注入和面向切面编程等特性,简化了Java应用程序的开发过程。 以下是关于Spring学习的一些笔记: 1. IoC(控制反转):Spring通过IoC容器管理对象的创建和依赖关系的注入。通过配置文件或注解,将对象的创建和依赖关系的维护交给Spring容器来管理,降低了组件之间的耦合度。 2. DI(依赖注入):Spring通过依赖注入将对象之间的依赖关系解耦。通过构造函数、Setter方法或注解,将依赖的对象注入到目标对象中,使得对象之间的关系更加灵活和可维护。 3. AOP(面向切面编程):Spring提供了AOP的支持,可以将与业务逻辑无关的横切关注点(如日志、事务管理等)从业务逻辑中分离出来,提高了代码的可重用性和可维护性。 4. MVC(模型-视图-控制器):Spring提供了一个MVC框架,用于构建Web应用程序。通过DispatcherServlet、Controller、ViewResolver等组件,实现了请求的分发和处理,将业务逻辑和视图展示进行了分离。 5. JDBC和ORM支持:Spring提供了对JDBC和ORM框架(如Hibernate、MyBatis)的集成支持,简化了数据库访问的操作,提高了开发效率。 6. 事务管理:Spring提供了对事务的支持,通过声明式事务管理和编程式事务管理,实现了对数据库事务的控制和管理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值