Spring 创建及配置、依赖注入

spring特点

(1)方便解耦,简化开发(对象与对象的调用)

(2)AOP的支持

(3)测试方便

(4)和其他框架进行整合

(5)方便对事物的操作

(6)降低api的开发难度。

spring核心组成部分

IOC 和 AOP

IOC

控制反转,也就是把创建对象的过程、对象与对象的调用过程统统交给spring来做,以后想用一个对象不需要new 了,本质上它是一个容器,而所谓的容器就是一个工厂,在工厂里边,获取xml解析的class属性值,通过反射来获取类字节码文件,进而获取配置类的相关属性。

目的

降低耦合。

IOC底层原理

(1) XML解析、工厂模式???、反射(通过反射获取更加灵活)



IOC接口(BeanFactory)

IOC思想是基于IOC容器完成,而IOC容器最底层就是一个对象工厂。
spring 提供的IOC容器实现的两种方式,两个都是接口
(1)BeanFactory
它是spring内部使用的,不提供给开发用,在加载配置文件时,不会创建对象,而读取对象(使用)采取创建对象。
(2)ApplicationContext
 BeanFactory接口的子接口,提供了更加强大的功能,共开发人员使用,在加载配置文件的时候,就会把配置文件中的对象创建出来。
两个接口都可以通过工厂模式,通过加载配置文件,来创建对象。

ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
// 或
BeanFactory ctx = new ClassPathXmlApplicationContext("beans.xml");

下边着重看下,ApplicationContext接口的实现类:
(1)ClassPathXmlApplicationContext,这个类我们上边用到了,会去加载、创建一个对象
(2)FileSystemXmlApplicationContext,这个实现类跟第一个一样,会创建一个对象,

ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext区别:
ClassPathXmlApplicationContext 参数路径(配置文件)必须在src目录下,表示类路径;
FileSystemXmlApplicationContext 参数路径(配置文件)放在某个盘符的目录下,且必须时绝对路径才行。

IOC操作Bean管理

什么是Bean管理

指的是两个操作:

(1)spring创建对象
(2)spring对属性进行注入

Bean管理的两种方式

(1)基于xml配置文件的方式实现
(2)基于注解的方式

xml方式创建对象及属性的注入
id :标识符
class:类全路径

public class Person {
    private String name;
    public void name(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
<bean id="person" class="com.lxc.domain.Person">
    <property name="name" value="lxc" />
</bean>

传统的注入属性的方式,前提:必须呀new Person() 才能调用:

(1)通过set方法

public class Person {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
}

(2)通过有参构造注入

public class Person {
    private String name;
    public void name(String name) {
        this.name = name;
    }
}

spring注入属性的方式,不需要new Person()即可完成对象的创建及属性注入:

(1)下边是无参构造的方式注入属性值(底层是调用的setName方法)

<bean id="person" class="com.lxc.domain.Person">
    <!--注入属性-->
    <property name="name" value="lxc" />
</bean>

(2)下边是有参构造的方式注入属性值(底层是调用有参的构造方法)
提示:当无参构造和有参构造同时给一个属性注入值时,无参构造优先级高。

<bean id="person" class="com.lxc.domain.Person">
    <!--无参构造属性值的注入-->
    <property name="name" value="lxc" />
    <!--有参构造属性值的注入-->
    <constructor-arg name="name" value="123" />
    <!--下边效果与上边一样,著不过时通过参数索引注入值的-->
    <constructor-arg index="0" value="123" />
</bean>

Bean的作用域

在spring里边,设置创建bean实例是单实例还是多实例。

默认情况下创建的bean是单例模式。

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="person" class="com.lxc.domain.Person">
        <property name="name" value="lxc" />
    </bean>
</beans>
public class Test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        Person person = ctx.getBean("person", Person.class);
        System.out.println(person == person); // true
    }
}

多实例情况:
通过scope属性来设置。

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="person" class="com.lxc.domain.Person" scope="prototype">
        <property name="name" value="lxc" />
    </bean>
</beans>

********** Bean的生命周期 ********** 

从对象的创建到对象销毁的过程。
大致分7步:

(1)默认是通过无参构造器来创建bean实例;
(2)为Bean的属性和对引用的Bean 设置值;

把bean实例传递给bean后置处理器 postProcessBeforeInitialization 方法中处理; 
(3)调用Bean初始化方法(需要对其配置);
把bean实例传递给bean后置处理器 postProcessAfterInitialization 方法中处理;
(4)bean就可以使用了(对象已经获取到);
(5)当容器关闭时,调用bean里边销毁方法(需要配置销毁方法)。

演示生命周期
提示:在演示过程中,如果前后置处理器出发了多次,一定是xml中的配置有多个bean,因为一个bean初始化时生命周期就会加载一次!

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean id="cat" class="com.lxc.domain.Cat" />
    <bean id="dog" class="com.lxc.domain.Dog" />
    <bean id="person" class="com.lxc.domain.Person" init-method="initMethod" destroy-method="destroyMethod">
        <property name="name" value="lxc" />
    </bean>
 <!--配置后置处理器-->
    <bean id="beanPost" class="com.lxc.domain.MyBeanPost" />

</beans>
public class Person {
    private String name;

    public Person() {
        System.out.println("第一步 调用无参构造创建Bean实例");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        System.out.println("第二步 调用set方法设置属性值");
        this.name = name;
    }
    public void initMethod() {
        System.out.println("第三步 调用初始化方法");
    }
    public void destroyMethod() {
        System.out.println("最后 执行销毁方法");
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

 模拟bean的后值处理器,必须实现 BeanPostProcessor  接口,且重写里边两个方法。

// 模拟bean的前后置处理器 方法必须实现 BeanPostProcessor 接口,且重写里边的2个方法
public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("bean后置处理器方法 postProcessBeforeInitialization 执行了");
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("bean后置处理器方法 postProcessAfterInitialization 执行了");
        return null;
    }
}
public class Test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        Person person = ctx.getBean("person", Person.class);
        System.out.println("第四步 获取创建的bean实例对象: "+person);
        // 手动调用销毁方法
        ((ClassPathXmlApplicationContext) ctx).close();
    }
}

IOC操作Bean管理(xml自动装配)
提示:在实际开发中,是基于注解方式做自动装配,很少用xml方式。

根据指定装配规则(属性名或者属性类型),spring自动将匹配的属性值进行注入。

先来看一个我们之前写的手动装配的简单小例子:

public class Person {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
<bean id="person" class="com.lxc.domain.Person">
    <property name="name" value="lxc" /> <!--属性和属性值手动装配-->
</bean>

自动装配
自定装配,需要在bean标签添加 autowire属性,配置自动装配。

autowire属性常用的两只属性值:
byname - 根据属性名称注入,;
byType - 根据属性类型注入,;

<bean id="person" class="com.lxc.domain.Person" autowire="byName" />
<bean id="father" class="com.lxc.domain.Father" />
public class Person {
    private Father father1;
    public Father getFather() {
        return father1;
    }
    public void setFather(Father father) {
        this.father1 = father;
    }
    @Override
    public String toString() {
        return "Person{" +
                "father=" + father1 +
                '}';
    }
}
public class Father {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

IOC操作Bean管理(基于注解的)

代码的特殊标记。

用注解目的

简化操作。

在spring中,针对Bean管理中创建对象的注解有以下几个

@Component

@Service

@Controller

@Repository 或 @Mapper

以上几个注解,功能是一样的,都可以来创建Bean的实例。

基于注解的方式来创建对象

第一步

引入依赖

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启注解支持-->
    <context:annotation-config/>
    <!--开启组件的扫描,扫描多个包,包之间要用逗号隔开, 或者扫描上层目录-->
    <context:component-scan base-package="com.lxc.domain" />

</beans>

第二步

开启组件扫描,同上。

第三步

在类上添加创建对象的注解。
提示:注解中的value值可以不写,默认值是下边类名的首字母小写的形式,下边使用@Service或者 @Controller或者 @Repository 注解都可以。

// 里边的value相当于之前 <bean id="person"> id的值,当然value也可以省略,
// 如果省略,默认value值是下边类名的小写形式
@Component(value = "person")
public class Person {
    public void t() {
        System.out.println("123");
    }
}

第四步

测试

public class Test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        Person person = ctx.getBean("person", Person.class);
        person.t();
    }
}


属性注入

基于注解方式实现属性注入的注解有以下几个

@Autowired
根据属性类型进行注入;

用法
以Father和Person类为例,来看下以注解的方式如何进行属性注入

第一步:

在两个类上添加创建对象注解。

@Repository
public class Father {
    public void say() {
        System.out.println("我是爸爸");
    }
}

 第二步:

天机注入属性的注解,即可

@Service
public class Person {
    @Autowired
    private Father father;

    public void add() {
        father.say();
    }
}

第三步:

测试

public class Test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        Person person = ctx.getBean("person", Person.class);
        person.add();
    }
}

@Auqlifier
根据属性名称进行注入,这个必须要跟@Autowired 一起来使用;

@Service
public class Person {
    @Autowired
    @Qualifier("father")
    private Father father;
    
    public void add() {
        father.say();
    }
}

@Resource
根据属性类型或者名称都可以注入;

@Value
注入普通类型属性。

@Service
public class Person {
    // 123 会被注入到属性中去name
    @Value(value = "123")
    private String name;
    public void add() {
        System.out.println(name);
    }
}

测试

在实际开发中,通过 @Value 可以动态读取配置文件中的端口号,或是一些配置属性等等。
前提:是springboot项目。

@Value("${names}")
private String name;

完全用注解的方式开发,舍弃xml

(1)第一步

这种方式,需要创建一个配置类,来替代xml文件,

package com.lxc.domain;


import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration // 这个注解的作用就是告知spring,这是一个配置类,替换之前的 bean.xml的
@ComponentScan(basePackages = "com.lxc") // 这个就是要扫描哪一个包下的文件 ,等于之前 xml中的 <context:component-scan base-package="com.lxc" />
public class SpringConfig {
}

(2)第二步

测试, 注意的是与之前不同,下边 new  AnnotationConfigApplicationContext(xx.class) 获取配置类

public class Test {

        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        Person person = ctx.getBean("person", Person.class);
        person.add();
    }
}

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

以上是最近补充的内容,下边是之前记录的。

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

创建

记录创建过程,四步:

第一步:

想要使用spring,必须maven安装依赖:

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.8</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.8</version>
    </dependency>
</dependencies>

第二步:

创建实体类

package com.lxc.domain;
public class User {
    private String name;
    private int age;
    public User() {}
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

第三步:

resource下创建 beans.xml文件,使用srping之前,必须配置的,配置如下:

<?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来创建对象
    下边是无参构造方法设置:
    <bean> 标签:====================================================
    bean: 相当于一个对象 , new User()
    id: 这个对象的唯一标识
    class: 这个对象的类型,必须写 全路径名称
    <property> 标签:====================================================
    name属性:值就是实体类中的属性名
    value属性: 为属性设置的值
    
    有参构造方法设置:外层标签bean一样
    里边标签<constructor-arg>
    name:属性名;
    value: 属性值。
    index: 参数的索引,0代表: 参数一; 1代表:参数二; ··· ···
-->
    <!--无参构造-->
    <bean id="user" class="com.lxc.domain.User">
        <property name="name" value="吕星辰" />
        <property name="age" value="20" /> 
    </bean>
    
    <!--有参构造:方法一:通过参数名来设置-->
    <!--<bean id="user" class="com.lxc.domain.User">
        <constructor-arg name="name" value="lxc;" />
    </bean>-->
    
    <!--有参构造:方法二:通过参数的索引来设置参数-->
    <!--<bean id="user" class="com.lxc.domain.User">
        <constructor-arg index="0" value="l" />
        <constructor-arg index="1" value="20" />
    </bean>-->
</beans>

第四步:

测试调用,传统方式,如果想要使用User对象,必须把User类引入。然后new实例化之后,才能使用里边的方法属性等等,但是使用spring,上边配置完,就不需要实例化了,获取User类对象只需要两步,如下:

import com.lxc.domain.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        // (1)spring容器 - 加载上边的配置文件 beans.xml
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        // (2)getBean() 方法获取user对象,调用的时候,默认会执行 User类的无参构造方法,对User类实例化了
        User user = (User) ctx.getBean("user");
        System.out.println(user.toString()); // User{name='吕星辰', age=20}
    }
}

配置

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">
    
    <!--方法一:在bean标签中 添加name属性,也可以添加多个别名中间以空格或逗号分隔-->
    <bean id="user" class="com.lxc.domain.User" name="newUser,newUser1 newUser2">
        <property name="name" value="吕星辰" />
        <property name="age" value="20" />
    </bean>
    <!--方法二:通过别名 newUser也能获取到User类 -->
    <alias name="user" alias="newUser"/>
</beans>

2、import

团队开发,将多个配置文件,导入合并为一个

ApplicationContext.xml 总文件,可以通过import 来引入分支文件

<!--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">
    <import resource="beans.xml" />
    <import resource="beans1.xml"/>
</beans>

分支文件

依赖注入

1、set方式注入【重点】

之所以叫set注入,spring是通过实体类中各个属性的set方法为字段注入值的。

(1)注入null的情况
下边值注入一个name属性,其他的不注入,我们来看下输出的值:

创建实体类Student

package com.lxc.domain;
import java.util.*;
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private Map<String, String> card;
    private Set<String> games;
    private Properties info;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Address getAddress() {
        return address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
    public String[] getBooks() {
        return books;
    }
    public void setBooks(String[] books) {
        this.books = books;
    }
    public Map<String, String> getCard() {
        return card;
    }
    public void setCard(Map<String, String> card) {
        this.card = card;
    }
    public Set<String> getGames() {
        return games;
    }
    public void setGames(Set<String> games) {
        this.games = games;
    }
    public Properties getInfo() {
        return info;
    }
    public void setInfo(Properties info) {
        this.info = info;
    }
    // 字符串相加,所有的变量默认会调用 toString() 方法
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", Address='" + address + '\'' + '\n' +
                ", books=" + Arrays.toString(books) +
                ", card=" + card + '\n' +
                ", games=" + games +
                ", info=" + info +
                '}';
    }
}

创建实体类Address

package com.lxc.domain;
public class Address {
    private String country;
    private String province;
    private String city;
    public String getCountry() {
        return country;
    }
    public void setCountry(String country) {
        this.country = country;
    }
    public String getProvince() {
        return province;
    }
    public void setProvince(String province) {
        this.province = province;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    @Override
    public String toString() {
        return "Address{" +
                "country='" + country + '\'' +
                ", province='" + province + '\'' +
                ", city='" + city + '\'' +
                '}';
    }
}

 beans.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 id="student" class="com.lxc.domain.Student">
        <property value="Spring" name="name"/>
    </bean>
</beans>

测试调用

import com.lxc.domain.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        // spring容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans2.xml");
        // 方法一:
        Student student = (Student) ctx.getBean("student");
        // 方法二:参数二定义类的类型,就不需要强制转换了
        Student student = ctx.getBean("student", Student.class);
        System.out.println(student.toString());
    }
}

 输出如下:

(2)注入  bean方式(引用)、数组类型、Map集合类型、Set集合类型、Properties类型

beans.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 id="address" class="com.lxc.domain.Address">
        <property name="country" value="中国" />
        <property name="province" value="山东省" />
        <property name="city" value="烟台市" />
    </bean>
    <bean id="student" class="com.lxc.domain.Student">
        <!--普通注入方式:通过value注入-->
        <property name="name" value="Spring"/>

        <!--通过引用方式注入,address属性值引用的上边的address-->
        <property name="address" ref="address"/>

        <!--String[] 数组类型注入-->
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>水浒传</value>
                <value>三国演义</value>
            </array>
        </property>

        <!--Map类型注入-->
        <property name="card">
            <map>
                <entry key="学生卡" value="1100020" />
                <entry key="银行卡" value="111222000" />
            </map>
        </property>

        <!--Set类型注入-->
        <property name="games">
            <set>
                <value>英雄联盟</value>
                <value>地下城与勇士</value>
            </set>
        </property>

        <!--properties-->
        <property name="info">
            <props>
                <prop key="sex">男</prop>
                <prop key="height">170</prop>
                <prop key="class">三年级二班</prop>
            </props>
        </property>
    </bean>
</beans>

测试调用与上边一样,不贴出来了。

输出如下:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值