Spring-IOC

关于Spring-IOC,如果有错误,欢迎指正。

Spring-IOC

Spring的体系结构

Spring框架包含众多模块,如Web Servlet、Data Access、Core Container等,其中在Core Container(核心容器)模块中的Core核心模块,提供了Spring框架的基本组成部分,包括了IOC和DI功能。

上图的SpEl指的是Expression Language 模块:是运行时查询和操作对象图的强大的表达式语言。

Spring体系结构详解 (biancheng.net)

IOC和AOP作为Spring框架的核心,我们也要重点去学习。

一、什么是IOC

​ IOC(Inversion of Control)是控制反转是意思,是一种面向对象编程的设计思想。IOC可以把对象的创建和对象之间的调用过程,交给Spring进行管理,从而降低对象之间的耦合度。

二、IOC的底层原理

​ IOC的底层原理:xml解析、工厂模式、反射。

​ IOC实现原理:在工厂模式的基础上,利用xml配置文件,配置创建的对象,然后在工厂类的返回userDao对象的方法中,通过对xml解析获得 userDao 的类路径,再通过反射创建对象,最后返回对象。

​ 这种IOC的过程在工厂模式的基础上进一步降低了耦合度。

三、IOC(接口)

​ 1、IOC思想基于IOC容器完成,IOC容器底层就是对象工厂

​ 2、Spring提供IOC容器实现两种方式:

​ (1)BeanFactory:IOC容器基本实现,是Spring内部使用的接口,不供开发人员使用。

​ (2)ApplicationContext:BeanFactory接口的子接口,有更强大的功能。

在这里插入图片描述

​ BeanFactory与ApplicationContext的区别:

​ BeanFactory在加载配置文件时不会去创建对象,在(获取)使用对象的时候才会创建对象。

​ ApplicationContext在加载配置文件的时候就把配置文件对象进行创建。

​ ApplicationContext虽然会加长项目的启动时间,但在web项目运行时,可以减少加载时间和内存消耗,适合Web开发,推荐使用(耗时耗内存的都在项目启动的时候进行处理更加合适)。

​ 3、ApplicationContext接口实现类:

​ (1)ClassPathXmlApplicationContext:

​ 在new的时候需要指定类的路径(src下)

在这里插入图片描述

​ (2)FileSystemXmlApplicationContext

​ 盘的路径(例如:C://file.xml)

在这里插入图片描述

​ 4、BeanFactory

​ ConfigurableApplicationContext:该子接口中可以包括相关的扩展功能

在这里插入图片描述

四、IOC操作

在进行ioc操作之前先在我们的项目中引入spring的基本jar包(核心容器和日志)

在这里插入图片描述

在这里插入图片描述

在项目中导入这5个jar包
在这里插入图片描述

bean管理:

​ 什么是bean管理(两个操作):

​ 1、spring创建对象

​ 2、spring属性注入

bean管理操作(基于xml):

基于xml创建对象:

​ 在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建

​ bean常用属性:

​ (1)id: 唯一标识

​ (2)class: 类全路径(包类路径)

​ (3)name: 和id一样,但是可以增加 / 等特殊符号。

​ 创建对象的时候也是默认执行无参构造方法,完成对象创建

​ 没有无参构造会报错:

xml:

在这里插入图片描述

User:

在这里插入图片描述

基于xm属性注入:

DI:依赖注入,就是注入属性。

1、set方法进行注入:

(1)创建类,定义属性和对应set方法

public class User {
    private int id ;
    private String name;

    public void setId(int id) {
        this.id = id;
    }

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

(2)在spring配置文件中配置对象的创建,配置属性注入

​ 在property标签中注入

<bean id="user" class="com.songzhi.spring.User">
<!--        name的值为类中的属性名,value的值为属性名对应的值(向属性注入的值)-->
        <property name="id" value="123"></property>
        <property name="name" value="刀哥"></property>
</bean>

​ 在User类中加入toString方法:

public void toUserString(){
    System.out.println("UserId = "+id);
    System.out.println("UserName = "+name);
}

​ 测试类进行测试:

@Test
public void testAdd(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    User user = context.getBean("user",User.class);
    user.toUserString();
}

​ 输出效果:
在这里插入图片描述

2、有参构造进行注入:

(1)创建类,定义属性,创建属性对应有参构造方法:

public class User {
    private int id ;
    private String name;

    User(int id ,String name){
        this.id=id;
        this.name=name;
    }
    public void toUserString(){
        System.out.println("UserId = "+id);
        System.out.println("UserName = "+name);
    }
}

(2)在spring配置文件中进行配置

<bean id="user" class="com.songzhi.spring.User">
    <constructor-arg name="id" value="1"></constructor-arg>
    <constructor-arg name="name" value="小明"></constructor-arg>
</bean>

测试类与上面set方法测试类相同,输出结果:toset
在这里插入图片描述

3、p名称空间注入:

​ 使用p名称空间注入,可以简化基于xml配置方式

(1)添加p名称空间在配置文件中:

<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
	
</beans>

(2)进行属性注入,在bean标签里面进行操作:

<bean id="user" class="com.songzhi.spring.User"
    p:id="2" p:name="小红">
</bean>

注意:这种方式底层用的是set方法进行注入!!!

这次使用上面set方法进行注入的类,测试类也是用set方法进行注入的测试类。toset

输出结果:
在这里插入图片描述

xml注入其他类型属性:
1、字面量:

(1)NULL值

对user的name属性注入null:

<bean id="user" class="com.songzhi.spring.User">
    <property name="id" value="0"></property>
    <property name="name">
        <null/>
    </property>
</bean>

测试类和user类与上面set方法注入相同toset

输入结果:

在这里插入图片描述

(2)属性值包含特殊符号:

如果赋值中含有特殊符号有两种方式进行属性注入:

第一种:使用转义字符(&lt; &gt;)=>(< >)

<bean id="user" class="com.songzhi.spring.User">
    <property name="id" value="0"></property>
    <property name="name" value="&lt;&gt;">
    </property>
</bean>

测试类和user类与上面set方法注入相同toset

输出结果:
在这里插入图片描述

第二种:把带特殊符号内容写到CDATA当中去:(<![CDATA[特殊符号内容]]>

<bean id="user" class="com.songzhi.spring.User">
    <property name="id" value="0"></property>
    <property name="name">
        <value><![CDATA[<&*()>]]></value>
    </property>
</bean>

测试类和user类与上面set方法注入相同toset

输出结果:
在这里插入图片描述

2、注入属性-外部bean

如下图结构创建类和接口:

在这里插入图片描述

其中,UserDaoImpl类:

public class UserDaoImpl implements UserDao {

    @Override
    public void update() {
        System.out.println("UserDaoImpl update ......");
    }
}

UserDao类:

public interface UserDao {

    void update();

}

UserService类:

在service类中调用dao里面的方法。

public class UserService {
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void add(){
        System.out.println("service add ......");
        userDao.update();
    }
}

配置文件:

<bean id="userService" class="com.songzhi.spring.service.UserService">
    <property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.songzhi.spring.dao.impl.UserDaoImpl"></bean>

测试类:

@Test
public void testAdd(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    UserService userService = context.getBean("userService", UserService.class);
    userService.add();
}

输出结果:

在这里插入图片描述

这种spring的方式可以实现在Service的add方法中调用daoimpl中的方法。

原始的做法可以在add中加入:

UserDao userDao = new UserDaoImpl();
userDao.update();

这样利用多态也可以做到在service的方法中调用接口实现类的方法。

3、注入属性-内部bean:

(1)现在有一对多的关系:

​ 部门和员工,一个部门有多个员工,一个员工属于一个部门。

​ 一:部门,多:员工

(2)在实体类中表示一对多的关系:

/**
 * 部门类
 */
public class Dept {
    private String DName;

    public void setDName(String DName) {
        this.DName = DName;
    }
    @Override
    public String toString() {
        return "Dept{" +
                "DName='" + DName + '\'' +
                '}';
    }
}
/**
 * 员工类
 */
public class Emp {
    //姓名
    private String EName;
    //性别
    private String gender;
    //部门
    private Dept dept;

    public void setEName(String EName) {
        this.EName = EName;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }
    @Override
    public String toString() {
        return "Emp{" +
                "EName='" + EName + '\'' +
                ", gender='" + gender + '\'' +
                ", dept=" + dept.toString() +
                '}';
    }
}

(3)在spring配置文件中进行配置:

<bean id="emp" class="com.songzhi.spring.entity.Emp">
    <property name="EName" value="Li"></property>
    <property name="gender" value=""></property>
    <property name="dept">
        <bean id="dept" class="com.songzhi.spring.entity.Dept">
            <property name="DName" value="技术部"></property>
        </bean>
    </property>
</bean>

测试类:

@Test
public void testOne(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    Emp emp = context.getBean("emp",Emp.class);
    System.out.println(emp.toString());

}

输出结果:
在这里插入图片描述

4、注入属性-级联赋值:

第一种写法:外部bean:

<bean id="emp" class="com.songzhi.spring.entity.Emp">
    <property name="EName" value="wan"></property>
    <property name="gender" value=""></property>
    <!--级联赋值-->
    <property name="dept" ref="Dept"></property>
</bean>
<bean id="Dept" class="com.songzhi.spring.entity.Dept">
    <property name="DName" value="安保部"></property>
</bean>

其他部分与上面一样:toOthers

输出结果:
在这里插入图片描述

第二种写法:使用对象.属性的方式

这种方式会调用类中的get方法,所以我们要先在Emp类中生成get方法

public Dept getDept() {
    return dept;
}

xml:

<bean id="emp" class="com.songzhi.spring.entity.Emp">
    <property name="EName" value="lin"></property>
    <property name="gender" value=""></property>

    <property name="dept" ref="dept"></property>
    <property name="dept.DName" value="财务部"></property>
</bean>
<bean id="dept" class="com.songzhi.spring.entity.Dept">
    <property name="DName" value="安保部"></property>
</bean>

输出内容:

在这里插入图片描述

5、注入集合属性:

注入包括:数组类型,list集合类型,map集合类型

(1)创建类,定义数组、list、map、set,生成对应的set方法

public class Stu {
    //数组
    private String[] courses;
    //集合
    //list
    private List<String> lists;
    //map
    private Map<String,String> maps;
    //set
    private Set<String> sets;

    public void setCourses(String[] courses) {
        this.courses = courses;
    }

    public void setLists(List<String> lists) {
        this.lists = lists;
    }

    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }

    public void setSets(Set<String> sets) {
        this.sets = sets;
    }
    
    @Override
    public String toString() {
        return "Stu{" +
                "courses=" + Arrays.toString(courses) +
                ", lists=" + lists +
                ", maps=" + maps +
                ", sets=" + sets +
                '}';
    }
}

(2)在spring配置文件中进行配置

数组类型可以使用list标签或者array标签进行注入。

<bean id="stu" class="com.songzhi.spring.entity.Stu">
    <!--注入数组-->
    <property name="courses">
        <array>
            <value>数学</value>
            <value>英语</value>
        </array>
    </property>
    <!--注入list-->
    <property name="lists">
        <list>
            <value>60分</value>
            <value>90分</value>
        </list>
    </property>
    <!--注入map-->
    <property name="maps">
        <map>
            <entry key="JAVA" value="java"></entry>
            <entry key="Python" value="python"></entry>
        </map>
    </property>
    <!--注入set-->
    <property name="sets">
        <set>
            <value>体育部长</value>
            <value>学生会长</value>
        </set>
    </property>
</bean>

(3)测试类:

@Test
public void testTwo(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    Stu stu =context.getBean("stu",Stu.class);
    System.out.println(stu.toString());
}

输出结果:

在这里插入图片描述

细节:

在list集合中放入对象类型:

实体类:

public class Teacher {
    private List<Course> courses;

    public void setCourses(List<Course> courses) {
        this.courses = courses;
    }
    public void toTeacherString(){
        for (Course course : courses) {
            System.out.println(course.toString());
        }
    }
}
public class Course {
    private String cname;

    public void setCname(String cname) {
        this.cname = cname;
    }
    @Override
    public String toString() {
        return "Course{" +
                "cname='" + cname + '\'' +
                '}';
    }
}

配置文件:

<bean id="teacher" class="com.songzhi.spring.entity.Teacher">
    <property name="courses">
        <list>
            <ref bean="course1"/>
            <ref bean="course2"/>
        </list>
    </property>
</bean>
<bean id="course1" class="com.songzhi.spring.entity.Course">
    <property name="cname" value="JAVA"></property>
</bean>
<bean id="course2" class="com.songzhi.spring.entity.Course">
    <property name="cname" value="TypeScript"></property>
</bean>

test类:

@Test
public void testThree(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    Teacher teacher = context.getBean("teacher",Teacher.class);
    teacher.toTeacherString();
}

在这里插入图片描述

注意:

内部的property只能在当前bean中使用,需要把里面的property分别抽取出来,作为公共部分来使用。

把集合注入部分提取出来:

(1)在spring配置文件中引入名称空间util

新建一个bean.xml,引入名称空间util

<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-util.xsd">
        

</beans>

(2)使用util标签完成list集合注入提取

<bean id="stu" class="com.songzhi.spring.entity.Stu">
    <!--注入数组-->
    <property name="courses" ref="course"/>
    <!--注入list-->
    <property name="lists" ref="list"/>
    <!--注入map-->
    <property name="maps" ref="map"/>
    <!--注入set-->
    <property name="sets" ref="set"/>
</bean>

<util:list id="course">
    <value>数学</value>
    <value>英语</value>
</util:list>

<util:list id="list">
    <value>60分</value>
    <value>90分</value>
</util:list>

<util:map id="map">
    <entry key="JAVA" value="java"></entry>
    <entry key="Python" value="python"></entry>
</util:map>

<util:set id="set">
    <value>体育部长</value>
    <value>学生会长</value>
</util:set>

这样的话就可以在公共使用值了

6、FactoryBean

FactoryBean是Spring容器提供的一种可以扩展容器对象实例化逻辑的接口,与BeanFactory不同,这里的Bean是生产对象的工厂。

应用场景:

​ FactoryBean 通常是用来创建比较复杂的bean,一般的bean 直接用xml配置即可,但如果一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,用xml配置比较困难,这时可以考虑用FactoryBean。

Spring中有两种bean:普通bean和工厂bean

普通bean:

在配置文件中定义bean类型就是返回类型

工厂Bean:

在配置文件中定义bean类型可以和返回类型不一样

​ 工厂bean中的三个方法:

public String getObject() throws Exception:该方法返回该FactoryBean“生产”的对象。我们需要实现该方法以给出自己对象实例化逻辑

public Class<?> getObjectType():该方法仅返回getObject()方法所返回的对象的类型。如果预先无法确定,则返回null

public boolean isSingleton() :该方法返回结果用于表明,getObject()“生产”的对象是否要以singleton(单例)形式存于容器中。如果以singleton形式存在,则返回true,否则返回false

第一步:创建类,让这个类作为工厂Bean,实现接口FactoryBean

public class MyBean implements FactoryBean<Course> {
    @Override
    public Course getObject() throws Exception {
        return null;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }
}

在getObject方法中可以定义返回bean

第二步:实现接口里面的方法,在实现的方法中定义返回的bean类型:

@Override
public Course getObject() throws Exception {
    Course course = new Course();
    course.setCname("abc");
    return course;
}

xml:

<bean id="myBean" class="com.songzhi.spring.Bean.MyBean">
    </bean>

测试类:

@Test
public void testFour(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
    Course course = context.getBean("myBean",Course.class);
    System.out.println(course.toString());
}

实体类:

public class Course {
    private String cname;

    public void setCname(String cname) {
        this.cname = cname;
    }

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

输出结果:

在这里插入图片描述

Bean的作用域以及生命周期:
作用域:

在Spring里面,设置bean实例是单实例还是多实例:

Spring中,默认情况下bean是单实例对象:

@Test
public void test1(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
    Course course1 = context.getBean("course",Course.class);
    Course course2 = context.getBean("course",Course.class);
    System.out.println(course1);
    System.out.println(course2);
}
public class Course {
    private String cname;

    public void setCname(String cname) {
        this.cname = cname;
    }
}
<bean id="course" class="com.songzhi.spring.entity.Course">
    <property name="cname" value="123"/>
</bean>

输出结果:

在这里插入图片描述

由此可见默认是单实例模式,两个对象输出的地址相同。

设置单实例和多实例的方法:

在spring配置文件bean标签里面有属性(scope)用于 设置单实例还是多实例:

在这里插入图片描述

prototype是多实例,singleton是单实例。

在bean标签中设置多实例:

<bean id="course" class="com.songzhi.spring.entity.Course" scope="prototype">
    <property name="cname" value="123"/>
</bean>

设置多实例之后的输出:
在这里插入图片描述

singletonprototype的区别:

第一个singleton是单实例prototype是多实例;

第二个设置scope是singleton是时候,加载spring配置文件的时候就会创建单实例的对象;

设置scope是prototype的时候,不是在加载spring配置文件的时候创建对象,在调用getBean方法的时候创建多实例对象;

下面两个类型只适用于web程序:

request:表示一次请求,每次创建对象会放进request对象当中。

session:一次会话,每次创建对象会放进session对象当中。

关于scope其他类型的详细介绍:

spring中的scope详解 - 山高我为峰 - 博客园 (cnblogs.com)

bean生命周期(7步):

从对象创建到对象销毁的过程叫做生命周期(创建、注入、初始化、使用、销毁)

(1)通过构造器创建bean实例(无参数构造):

public class Life {

    public Life(){
        System.out.println("第一步:执行无参构造创建bean实例。");
    }
}

(2)为bean 的属性设置值,和对其他bean 的引用(调用set方法)

public class Life {

    private String LifeName;

    public Life(){
        System.out.println("第一步:执行无参构造创建bean实例。");
    }

    public void setLifeName(String lifeName) {
        LifeName = lifeName;
        System.out.println("第二步:调用set方法设置属性值。");
    }
}

(3)调用bean 的初始化的方法(需要进行配置初始化的方法)

在life中定义销毁的方法:

public void initMethod(){
    System.out.println("第三步:执行初始化的方法。");
}

在xml中引入:

<bean id="life" class="com.songzhi.spring.Bean.Life" init-method="initMethod">
    <property name="lifeName" value="lifeName的value"></property>
</bean>

(4)bean可以使用了(对象获取到了)

@Test
public void testLife(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
    Life life = context.getBean("life",Life.class);
    System.out.println("第四步:获取创建bean实例化对象");
    System.out.println("使用life中:"+life);
    //手动销毁bean实例
    ((ClassPathXmlApplicationContext)context).close();
}

(5)当容器关闭的时候,调用bean中销毁的方法(需要进行配置销毁的方法)

手动创建销毁的方法:

public void destroyMethod(){
    System.out.println("第五步:执行销毁的方法。");
}

xml中引入:

<bean id="life" class="com.songzhi.spring.Bean.Life" init-method="initMethod" destroy-method="destroyMethod">
    <property name="lifeName" value="lifeName的value"></property>
</bean>

在测试类中手动销毁bean实例:

//手动销毁bean实例
((ClassPathXmlApplicationContext)context).close();

测试结果:

在这里插入图片描述

上面一共是5步,算上下面的后置处理器是七步:

bean的后置处理器:把bean实例传递bean后置处理器的方法,此方法在初始化分别前后,有两个方法

一个是postProcessBeforeIntialization

一个是postProcessAfterIntialization

后置处理器:

创建MyBeanPost类:

public class MyBeanPost implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化之前执行的方法。");
        return bean;
    }
    public  Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化之后执行的方法。");
        return bean;
    }

}

在xml中配置后置处理器:

<bean id="myBeanPost" class="com.songzhi.spring.Bean.MyBeanPost"></bean>

输出结果:

在这里插入图片描述

第一步:执行无参构造创建bean实例。
第二步:调用set方法设置属性值。
第三步:在初始化之前执行的方法。
第四步:执行初始化的方法。
第五步:在初始化之后执行的方法。
第六步:获取创建bean实例化对象
使用bean
第七步:执行销毁的方法。

xml方式的自动装配:

什么是自动装配:

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

基于xml文件的自动装配:byType(类型),byName(名称), constructor(构造函数)

自动装配过程:

根据属性名称自动注入(byName):

<bean id="emp" class="com.songzhi.spring.entity.Emp" autowire="byName"></bean>
<bean id="dept" class="com.songzhi.spring.entity.Dept" ></bean>

设置属性为byName,那么spring会根据class属性找到对应实体类,然后查询实体类中所有的set方法的名字,根据set方法后面的名字(比如setName方法后面的名字就是Name)再到配置文件中寻找一个与该名字相同id的bean(id=“Name”),注入进来。

根据属性类型进行自动注入(byType):

<bean id="emp" class="com.songzhi.spring.entity.Emp" autowire="byType"></bean>
<bean id="dept" class="com.songzhi.spring.entity.Dept" ></bean>

设置autowire属性为byType,那么Spring会自动寻找一个与该属性类型相同的Bean(class值中"."的最后一个,例如class="com.songzhi.spring.entity.Emp"的类型就是Emp),注入进来。

*注意:使用byType这种方式,必须保证配置文件中所有bean的class属性的值是唯一的,否则就会报错。(就是xml中的bean标签的class的值必须都不一样)。

外部属性文件:

直接配置数据库信息:

引入德鲁伊jar包:

在这里插入图片描述

配置德鲁伊连接池;

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/jdbctext"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</bean>

引入外部属性文件配置数据库连接池:

(1)创建外部属性文件properties格式文件,数据库连接信息

prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/jdbctext
prop.username=root
prop.password=123456

等号前面的名字可以随便写,但为了防止名称冲突使用prop点的方式命名

(2)把外部的properties文件引入到spring配置文件中来:

引入context名称空间

<?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配置文件中使用标签引入外部配置文件

<!--    在spring配置文件中使用标签引入外部配置文件-->
    <context:property-placeholder location="classpath:Application.properties"/>
<!--    配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${prop.driverClass}"/>
        <property name="url" value="${prop.url}"/>
        <property name="username" value="${prop.username}"/>
        <property name="password" value="${prop.password}"/>
    </bean>

IOC(bean管理)基于注解:

1、什么是注解:

(1)注解是代码特殊标记

​ 格式:@注解名( 属性名=属性值,属性名=属性值,。。。)

(2)注解在什么什么时候用:

​ 类上面、方法上面、属性上面

(3)使用注解的目的

​ 简化xml配置

2、Spring针对Bean管理中创建对象提供注解:
  • @Component
    • 普通注解,创建对象
  • @Service
    • 用在业务逻辑层/Service层上
  • @Controller
    • 用在Web层上
  • @Repository
    • 用在Dao层或Mapper上
  • 上面四个注解功能是一样的,都可以用来创建bean
3、基于注解方式实现对象的创建:
1、引入依赖:

在这里插入图片描述

2、开启组件扫描:
<?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.songzhi"/>

</beans>
3、创建类,在类上面添加创建对象注解:
/**
 * 在注解里面value属性值可以省略不写
 * 默认是类名称,首字母小写
 */
@Component(value = "manService")
public class ManService {
    public void add(){
        System.out.println("ManService add......");
    }
}
4、开启组件扫描细节配置:

1、

<!--    use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter-->
<!--    context:include-filter ,设置扫描哪些内容-->
    <context:component-scan base-package="com.songzhi" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

2、

<!--    下面配置扫描包所有内容-->
<!--    context:exclude-filter: 设置哪些内容不进行扫瞄-->
    <context:component-scan base-package="com.songzhi">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
5、基于注解方式实现属性注入:

@AutoWired

根据属性类型自动注入

1、把service和dao对象创建,在service和dao类添加创建对象注解

2、在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解

<context:component-scan base-package="com.songzhi" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
@Component
public interface UserDao {

    void update();

}
@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public void add(){
        System.out.println("service add ......");
        userDao.update();
    }
}

@Qualifier

根据属性名称注入

这个注解的使用要和上面的Autowired一起使用

@Service
public class UserService {

    @Autowired//根据类型进行注入
    @Qualifier(value = "userDaoImpl")//根据名称进行注入
    private UserDao userDao;

    public void add(){
        System.out.println("service add ......");
        userDao.update();
    }
}
@Component
public class UserDaoImpl implements UserDao {

    @Override
    public void update() {
        System.out.println("UserDaoImpl update ......");
    }
}

@Resource(Javax)

根据属性类型和属性名称注入

只写resource默认根据类型进行注入

<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
//    @Resource//根据类型进行注入
    @Resource(name = "userDao")//根据名称进行注入
    private UserDao userDao
@Repository(value = "userDao")
public class UserDaoImpl implements UserDao {

    @Override
    public void update() {
        System.out.println("UserDaoImpl update ......");
    }
}

@Repository(value=“userDao”)注解是告诉Spring,让Spring创建一个名字叫“userDao”的UserDaoImpl实例。
当Service需要使用Spring创建的名字叫“userDao”的UserDaoImpl实例时,就可以使用@Resource(name = “userDao”)注解告诉Spring,Spring把创建好的userDao注入给Service即可。
@Repository原文链接:https://blog.csdn.net/weixin_39426138/article/details/77679912

Value

注入普通类型属性

@Value(value = "abc")
private String name;
6、完全注解开发:

(1)创建配置类,替代xml配置文件

@Configuration  //作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.songzhi"})
public class SpringConfig {

}

(2)编写测试类

@Test
public void test6(){
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    UserService userService = context.getBean("userService",UserService.class);
    System.out.println(userService);
    userService.add();

}

其他类:

@Service
public class UserService {

//    @Autowired//根据类型进行注入
//    @Qualifier(value = "userDaoImpl")//根据名称进行注入
//    @Resource//根据类型进行注入
    @Resource(name = "userDao")//根据名称进行注入
    private UserDao userDao;

    @Value(value = "abc")
    private String name;

    public void add(){
        System.out.println("注入的name的值为:"+name);
        System.out.println("service add ......");
        userDao.update();

    }
}
@Component
public interface UserDao {

    void update();

}
@Repository(value = "userDao")
public class UserDaoImpl implements UserDao {



    @Override
    public void update() {
        System.out.println("UserDaoImpl update ......");
    }
}

输出结果:
在这里插入图片描述

学习源自:尚硅谷Spring框架视频教程(spring5源码级讲解)_哔哩哔哩_bilibili

Spring官网:Spring | Home

(1)创建配置类,替代xml配置文件

@Configuration  //作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.songzhi"})
public class SpringConfig {

}

(2)编写测试类

@Test
public void test6(){
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    UserService userService = context.getBean("userService",UserService.class);
    System.out.println(userService);
    userService.add();

}

其他类:

@Service
public class UserService {

//    @Autowired//根据类型进行注入
//    @Qualifier(value = "userDaoImpl")//根据名称进行注入
//    @Resource//根据类型进行注入
    @Resource(name = "userDao")//根据名称进行注入
    private UserDao userDao;

    @Value(value = "abc")
    private String name;

    public void add(){
        System.out.println("注入的name的值为:"+name);
        System.out.println("service add ......");
        userDao.update();

    }
}
@Component
public interface UserDao {

    void update();

}
@Repository(value = "userDao")
public class UserDaoImpl implements UserDao {



    @Override
    public void update() {
        System.out.println("UserDaoImpl update ......");
    }
}

输出结果:

在这里插入图片描述

学习源自:尚硅谷Spring框架视频教程(spring5源码级讲解)_哔哩哔哩_bilibili

Spring官网:Spring | Home

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值