跳到正文
Kale的数字花园
目录 文章
/15 分钟/4 阅读/0 评论

Spring01-IOC

2006年10月,发布 Spring2.0 2009年12月,发布 Spring3.0 2013年12月,发布 Spring4.0 2017年9月, 发布最新 Spring5.0 通用版(GA) Spring 除了不能帮我们写业务逻辑.其余

什么是Spring

Spring是分层的 Java SE/EE应用 **full-stack(全栈) 轻量级开源框架**。
Spring的核心是 **IOC**(Inverse Of Control:控制反转)和 **AOP**(Aspect Oriented Programming:面向切面编程)
Spring一个全栈应用框架, 提供了表现层 Spring MVC 和持久层 Spring JDBC 以及业务层事务管理等众多应用技术
Spring还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架 
==Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技术==

为什么要学习Spring

最大程度的简化了开发
spring是一个非常优秀的java框架,其目标是为了简化java企业级开发,spring出来已经二十几年了,这期间也一直围绕着这个目标在进行,像后面需要学习的springmvc、springboot、springcloud,这些技术也都是围绕着简化开发的目标在努力,到目前为止已经做的足够好了,可以说spring除了不能帮助我们实现业务逻辑代码之外,其他的事情spring都尽量去帮我们简化了,使用spring可以帮助我们节约大量开发时间。

不使用spring的情况下,开发一个项目可能需要2个月,用了spring可能1个月都不需要,你说这样的技术你想学么?
大量公司使用
目前99%的公司使用了spring,可以去各大招聘网站看一下,spring算是必备技能,所以一定要掌握。
顶尖的源代码
spring框架源码设计非常优秀,在java开源项目中可以说是顶级的,目前为止还未发现比spring更优秀的开源项目,所以想提升代码能力的,强烈建议多看看spring的源码;关于提升代码能力的,还可以去看一下jdk的源码,也是非常棒的,里面有很多大师的杰作。

Spring的发展历程

要谈Spring的历史,就要先谈J2EE。J2EE应用程序的广泛实现是在1999年和2000年开始的,它的出现带来了诸如事务管理之类的核心中间层概念的标准化,但是在实践中并没有获得绝对的成功,因为开发效率,开发难度和实际的性能都令人失望。

		曾经使用过EJB开发JAVAEE应用的人,一定知道,在EJB开始的学习和应用非常的艰苦,很多东西都不能一下子就很容易的理解。EJB要严格地实现各种不同类型的接口,类似的或者重复的代码大量存在。而配置也是复杂和单调,同样使用JNDI进行对象查找的代码也是单调而枯燥。虽然有一些开发工作随着xdoclet的出现,而有所缓解,但是学习EJB的高昂代价,和极低的开发效率,极高的资源消耗,都造成了EJB的使用困难。而Spring出现的初衷就是为了解决类似的这些问题。

		Spring的形成,最初来自Rod  Jahnson所著的一本很有影响力的书籍《Expert One-on-One J2EE Design and  Development》,就是在这本书中第一次出现了Spring的一些核心思想,该书出版于2002年。2004年编著《Expert one-on-one J2EE Development without EJB》阐述了JavaEE开发时不使用EJB的解决方式(Spring 雏形),同年4月spring1.0诞生。

2006年10月,发布 Spring2.0  
2009年12月,发布 Spring3.0  
2013年12月,发布 Spring4.0  

2017年9月, 发布最新 Spring5.0 通用版(GA)

Spring的特点及优点

Spring 除了不能帮我们写业务逻辑.其余的几乎什么什么都能帮助我们简化开发

  • 方便解耦,简化开发通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
  • AOP编程的支持通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。
  • 声明式事务的支持在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
  • 方便程序的测试可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。
  • 方便集成各种优秀框架Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支持。
  • 降低Java EE API的使用难度Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。
  • Java 源码是经典学习范例Spring的源码设计精妙、结构清晰、匠心独运,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。Spring框架源码无疑是Java技术的最佳实践范例。如果想在短时间内迅速提高自己的Java技术水平和应用开发水平,学习和研究Spring源码将会使你收到意想不到的效果。

一句话概括:Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)

Spring体系结构

Spring IoC快速入门

Ioc引入

  • dao层
public interface UserDao {

    public void login();
}
public class UserDaoImpl implements UserDao {
    @Override
    public void login() {
        System.out.println("dao层登录成功!!!");
    }
}
  • service层
public interface UserService {
    public void login();
}
public class UserServiceImpl implements UserService {

    //注入业务层
    private UserDao userDao = new UserDaoImpl();

    @Override
    public void login() {
        System.out.println("业务层 登录!!!");
        //调用dao层方法
        this.userDao.login();
    }
}
  • 测试
public class UserServiceTest {
	//测试	
    @Test
    public void login() {
        UserService userService = new UserServiceImpl();
        userService.login();
    }
}

思考分析

【思考分析】
代码过于耦合,上层代码过度依赖于下一层代码的实现:
UserDAO userDAO = new UserDAOImpl(); 
如果要更换实现类,必须要修改原来的业务代码!
解决方案:采用IoC(Inverse of Control,控制反转)的思想。
简单的说就是引入工厂(第三者),将原来在程序中手动创建管理的依赖的UserDAO对象,交给工厂来创建管理。在Spring框架中,这个工厂就是Spring中的工厂,因此,也可以说,将创建管理UserDAO对象的控制权被反转给了Spring框架了。

IoC控制反转的实现

IoC本质

控制反转IoC(Inversion of Control),是一种设计思想,而不是一种新的技术。DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为

所谓控制反转就是:获得依赖对象的方式反转了
	IoC是Spring框架的核心内容`,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,
新版本的Spring也可以零配置实现IoC。

	Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用
时再从Ioc容器中取出需要的对象

IOC实现

添加spring相关依赖

<!--spring相关-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>5.2.9.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.2.9.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>5.2.9.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-expression</artifactId>
  <version>5.2.9.RELEASE</version>
</dependency>

<!--日志相关-->
<dependency>
  <groupId>commons-logging</groupId>
  <artifactId>commons-logging</artifactId>
  <version>1.1.1</version>
</dependency>
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.17</version>
</dependency>

核心配置文件

  • 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">

    <!--
        这就是spring的核心工厂

        如何让工厂创建一个对象呢?
            bean:   表示是一个对象/类; 相当于 new UserDaoImpl();
            id/name: 二选一,表示对象名,也是对外提供的唯一标识
            class:   表示你交给工厂的哪个类(全路径)
    -->

    <bean id="userDao" class="cn.yanqi.dao.impl.UserDaoImpl"/>
</beans>

获取Bean对象

/**
 * @Auther: yanqi
 * @Desc 业务层
 */
public class UserServiceImpl implements UserService {

    //注入业务层
    // private UserDao userDao = new UserDaoImpl();

    @Override
    public void login() {
        System.out.println("业务层 登录!!!");

        //现在要通过spring工厂来获取bean对象,如何获取呢?

        //1、找到bean对象所在的applicationContext.xml配置文件
        //ClassPathXmlApplicationContext 会默认加载resources下的applicationContext.xml
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        //2、找到工厂中bean的唯一标识
        //方式一
        UserDao userDao1 = (UserDao) applicationContext.getBean("userDao");

        //方式二
        UserDao userDao2 = applicationContext.getBean("userDao", UserDao.class);

        //方式三 通过找到接口类实现对象的创建,省去了bean的id或name --了解
        UserDao userDao3 = applicationContext.getBean(UserDao.class);
        UserDao userDao4 = applicationContext.getBean(UserDaoImpl.class);

        //调用dao层方法
        userDao3.login();
    }
}

DI依赖注入

DI  Dependency Injection 依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件
简单的说,可以将一个bean对象动态的注入到另外一个bean中

配置文件

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">

    
    <!--创建dao对象-->
    <bean id="userDao" class="cn.yanqi.dao.impl.UserDaoImpl"/>
    
    <!--创建service对象-->
    <bean id="userService" class="cn.yanqi.service.impl.UserServiceImpl">
        <!--
            在service层注入dao对象
            property:  属性注入对象
            name:      找到service层中提供的setXX方法,把set去掉,并把首字母小写
            ref:       你要注入的哪bean对象,bean的id/name
        -->
        <property name="userDao" ref="userDao"/>
    </bean>

</beans>

属性对象注入

  • service层
/**
 * @Auther: yanqi
 * @Desc 业务层
 */
public class UserServiceImpl implements UserService {

    //属性注入
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void login() {
        System.out.println("业务层 登录!!!");
        //调用dao层方法
        userDao.login();
    }
}

测试

/**
 * @Auther: yanqi
 * @Desc 测试类
 */
public class UserServiceTest {

    @Test
    public void login() {

        // UserService userService = new UserServiceImpl();
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        //获取bean对象
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.login();

    }
}

Spring核心接口

BeanFactory

这是IOC容器的顶级接口 它定义了IOC的最基础的功能, 但是其功能比较简单,一般面向Spring自身使用

在第一次使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化[用的时候再创建] --> 【懒汉设计】

ApplicationContext

这是在BeanFactory基础上衍生出的接口,它扩展了BeanFactory的功能,一般面向程序员使用

在容器启动时,一次性创建并加载了所有的Bean [初始化的时候全创建好] --> 【饿汉设计】

上面两种方式创建的对象都是单例, 只是创建对象的时机不同

public class UserServiceTest {
    @Test
    public void login() {
        // UserService userService = new UserServiceImpl();
        // ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

   //BeanFactory是bean工厂的顶级接口,了解即可
    BeanFactory beanFactory = new XmlBeanFactory(newClassPathResource("applicationContext.xml"));

    //获取bean对象
    UserService userService = beanFactory.getBean("userService", UserService.class);
    userService.login();

    }
}

IoC容器装配Bean_基于XML配置方式

实例化Bean的四种方式

第一种 无参数构造器 (最常用)

public class Bean1 {
}
<!--第一种: 无参构造-->
    <bean id="bean1" class="cn.yanqi.bean.Bean1"/>
@Test
    public void login() {
        //获取配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean对象
        Bean1 bean1 = applicationContext.getBean("bean1", Bean1.class);
        System.out.println(bean1);
    }

第二种 静态方式

public class Bean2 {
}
public class Bean2Test {
    //静态方式
    public static Bean2 initBean2(){
        return new Bean2();
    }
}
<!--第二种: 静态方法-->
    <!--相当于这里创建一bean2Test对象,直接调用了initBean2静态方法-->
    <bean id="bean2" class="cn.yanqi.bean.Bean2Test" factory-method="initBean2"/>
@Test
    public void login() {
        //获取配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean对象
        Bean2 bean2 = applicationContext.getBean("bean2", Bean2.class);
        System.out.println(bean2);
    }

第三种 普通方法

public class Bean3 {
}
public class Bean3Test {
    //普通方法
    public  Bean3 initBean3(){
        return new Bean3();
    }
}
<!--第三种: 普通方法-->
    <bean id="bean3Test" class="cn.yanqi.bean.Bean3Test"/>
    <!--找到bean3对象,通过bean3Test对象,调用initBean3()方法-->
    <bean id="bean3"  factory-bean="bean3Test" factory-method="initBean3"/>
@Test
    public void login() {
        //获取配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean对象
        Bean3 bean3 = applicationContext.getBean("bean3", Bean3.class);
        System.out.println(bean3);
    }

第四种 FactoryBean方式-了解

public class Bean4 {
}
/**
 * @Desc  实现FactoryBean接口
 */
public class Bean4Test implements FactoryBean<Bean4> {
    
    //返回bean对象即可
    @Override
    public Bean4 getObject() throws Exception {
        return new Bean4();
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }
}
<!--第四种: FactoryBean方式-->
    <bean id="bean4" class="cn.yanqi.bean.Bean4Test"/>
@Test
    public void login() {
        //获取配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean对象
        Bean4 bean4 = applicationContext.getBean("bean4", Bean4.class);
        System.out.println(bean4);
    }

Bean对象配置

相关属性

属性名 描述
id 在ioc容器的唯一标识
class 创建对象实例的全限定名
scope 声明此对象的作用范围 singleton:单例对象(默认) prototype:多例对象
init-method 在对象创建时,执行此方法
destroy-method 在对象销毁时,执行此方法

Bean的作用域

Singleton: 在一个spring容器中,对象只有一个实例。(默认值)

Prototype: 在一个spring容器中,存在多个实例,每次getBean 返回一个新的实例

public class SingletonBean {

    public SingletonBean() {
        System.out.println("我是单例。。。");
    }
}
public class PrototypeBean {

    public PrototypeBean() {
        System.out.println("我是多例。。。。");
    }
}
<!--spring默认是单例-->
    <!--单例-->
    <bean id="singletonBean" class="cn.yanqi.scope.SingletonBean" scope="singleton"/>

    <!--多例-->
    <bean id="prototypeBean" class="cn.yanqi.scope.PrototypeBean" scope="prototype"/>

测试

@Test
    public void login() {
        //获取配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
       
        //作用域
        SingletonBean singletonBean1 = applicationContext.getBean("singletonBean", SingletonBean.class);
        SingletonBean singletonBean2 = applicationContext.getBean("singletonBean", SingletonBean.class);
        System.out.println(singletonBean1);
        System.out.println(singletonBean2);

        PrototypeBean prototypeBean1 = applicationContext.getBean("prototypeBean", PrototypeBean.class);
        PrototypeBean prototypeBean2 = applicationContext.getBean("prototypeBean", PrototypeBean.class);
        System.out.println(prototypeBean1);
        System.out.println(prototypeBean2);
    }

Bean的生命周期

生命周期主要演示对象的创建和销毁时机!!!

需要用到两个属性: init-method 和 destroy-method

lifecycle

public class LifecycleDemo {
    
    public LifecycleDemo() {
        System.out.println("对象实例化了");
    }
    public LifecycleDemo(String name) {
    }

    public void initBean(){
        System.out.println("初始化");
    }

    public void DistroyBean(){
        System.out.println("over!!");
    }
}
<!--bean对象的生命周期-->
bean id="lifecycleDemo" class="cn.yanqi.lifecycle.LifecycleDemo" init-method="initBean" destroy-method="DistroyBean"/>
@Test
    public void login() {
        //获取配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        LifecycleDemo lifecycleDemo = applicationContext.getBean("lifecycleDemo", LifecycleDemo.class);
        System.out.println(lifecycleDemo);
    }

查看结果:

对象实例化了
初始化
我是单例。。。
cn.yanqi.lifecycle.LifecycleDemo@7b69c6ba

测试查看控制台打印,发现销毁方法没有执行。

原因:销毁方法的执行必须满足两个条件:
	1)	单例(singleton)的bean才可以手动销毁。
	2)	必须手动关闭容器(close)时,才会执行手动销毁的方法。
	
多例没就destroy-method 方法,只对单例有作用
  • 手动关闭
@Test
    public void login() {
        //获取配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        LifecycleDemo lifecycleDemo = applicationContext.getBean("lifecycleDemo", LifecycleDemo.class);
        System.out.println(lifecycleDemo);

        //使用junit调用时,当调用完毕时,junit会强制关jvm,但些时spring容器还没来的及关闭,所以不会有销毁方法
        //想要看到销毁方法,需要手动关闭
        ((ClassPathXmlApplicationContext)applicationContext).close();
    }

Bean属性的依赖注入

什么是Bean属性的注入?就是对 一个对象的属性赋值

constructor

构造方法注入

public class Car {

    private Integer id;
    private String name;
    private Double price;
	//提供有参无参构造方法,set get方法  toString方法
}
<bean id="car" class="cn.yanqi.constructor.Car">
        <constructor-arg name="id" value="1009"/>
        <constructor-arg name="name" value="滑板车"/>
        <constructor-arg name="price" value="99"/>
    </bean>
@Test
    public void login() {
        //获取配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        //传统写法
        Car car = new Car(1008,"单车",2d);
        System.out.println(car);

        //构造器属性注入
        Car car2 = applicationContext.getBean("car", Car.class);
        System.out.println(car2);
    }

set方法注入

<bean id="car" class="cn.yanqi.constructor.Car">
        <!--必须给set方法,name找的是对应的set方法-->
        <property name="id" value="1009"/>
        <property name="name" value="共享单车"/>
        <property name="price">
            <value>1.5</value>
        </property>
    </bean>

我再创建一个person对象

public class Person {
    private Integer id;
    private String name;
    private Car car;
    //提供有参无参构造方法,set get方法  toString方法
}
<bean id="car" class="cn.yanqi.constructor.Car">
        <!--必须给set方法,name找的是对应的set方法-->
        <property name="id" value="1009"/>
        <property name="name" value="共享单车"/>
        <property name="price" value="1.5"/>
    </bean>
    
    <bean id="person" class="cn.yanqi.constructor.Person">
        <property name="id" value="88"/>
        <property name="name" value="jack"/>
        <!--这里是引的car的bean对象-->
        <property name="car" ref="car"/>
    </bean>
@Test
    public void login() {
        //获取配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        //set属性注入
        Person person = applicationContext.getBean("person", Person.class);
        System.out.println(person);
    }

结果: Person{id=88, name='java', car=Car{id=1009, name='共享单车', price=1.5}}

P命名空间注入

p名称空间出现的目地为了简化以上两种注入方式

引入p名称空间约束头

<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:p="http://www.springframework.org/schema/p"
       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">
<!--p名称空间属性注入-->
    <bean id="person2" class="cn.yanqi.constructor.Person" p:id="99" p:name="rose" p:car-ref="car" />
@Test
    public void login() {
        //获取配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        //set属性注入
        Person person = applicationContext.getBean("person2", Person.class);
        System.out.println(person);
    }

查看结果: Person{id=99, name='rose', car=Car{id=1009, name='共享单车', price=1.5}}

集合类型属性注入

@Data
public class ConllectionBean {

    private List<String> list;
    private Set<Integer> set;
    private Map<Integer,String> map;
    private Properties properties;

}
<bean id="conllectionBean" class="cn.yanqi.constructor.ConllectionBean">
        <!--list-->
        <property name="list">
            <list>
                <value>aaa</value>
                <value>bbb</value>
                <value>ccc</value>
            </list>
        </property>

        <!--set-->
        <property name="set">
            <set>
                <value>11</value>
                <value>22</value>
                <value>33</value>
            </set>
        </property>

        <!--map-->
        <property name="map">
            <map>
                <entry key="11" value="aa"/>
                <entry key="22" value="bb"/>
                <entry key="33" value="cc"/>
            </map>
        </property>

        <!--properties-->
        <property name="properties">
            <props>
                <prop key="a">aa</prop>
                <prop key="b">bb</prop>
                <prop key="c">cc</prop>
            </props>
        </property>
    </bean>
@Test
    public void login() {
        //获取配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        //set属性注入
        ConllectionBean conllectionBean = applicationContext.getBean("conllectionBean", ConllectionBean.class);
        System.out.println(conllectionBean);
    }

IoC容器装配Bean_基于注解配置方式

spring-ioc-annotation

bean对象-注解

Spring 的【XML开发】和【注解开发】 导入依赖包是相同的

public interface UserDao {
    public void login();
}
@Component("userDao")// 相当于 <bean id="userDao" class="cn.yanqi.dao.impl.UserDaoImpl"/>
public class UserDaoImpl implements UserDao {
    @Override
    public void login() {
        System.out.println("dao层登录成功!!!");
    }
}
public interface UserService {
    public void login();
}
/**
@Component("userService") 
		相当于<bean id="userService" class="cn.yanqi.service.impl.UserServiceImpl"/>
		
@Autowired 
	相当于	   
        <bean id="userService" class="cn.yanqi.service.impl.UserServiceImpl">
            <property name="userDao" ref="userDao"/>
        </bean>
*/
@Component("userService")
public class UserServiceImpl implements UserService {
	
    //注入dao层对象
    @Autowired
    private UserDao userDao;

    @Override
    public void login() {
        System.out.println("业务层 登录!!!");

        userDao.login();
    }
}

applicationContext.xml

注意,这里用注释方式,约束引入context 名称空间

<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:annotation-config/>

    <!--
        扫描注解包 ,扫描包下含有@Component的类,就是bean对象
        <context:component-scan> 包含了 <context:annotation-config/>功能
    -->
    <context:component-scan base-package="cn.yanqi"/>
</beans>

Component-注解

@Component()是父注解
          三个子注解具有分层含义
               @Controller
               @Service
               @Repository
@Repository("userDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void login() {
        System.out.println("dao层登录成功!!!");
    }
}
@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    public void login() {
        System.out.println("业务层 登录!!!");

        userDao.login();
@Test
    public void login() {

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.login();
    }

Bean属性的依赖注入

  • 简单数据类型依赖注入@Value("22")
@Data
@Component
public class Car {
    @Value("22")
    private Integer id;

    @Value("单车")
    private String name;

    @Value("1.5")
    private Double price;
}
@Test
    public void login() {
       ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        Car car = applicationContext.getBean("car", Car.class);
        System.out.println(car);
    }

查看结果: Car(id=22, name=单车, price=1.5)

@Service("userService")
public class UserServiceImpl implements UserService {

    //第一种注入方式
    @Autowired

    //第二种注入方式
    // @Resource
    private UserDao userDao;

    @Override
    public void login() {
        System.out.println("业务层 登录!!!");

        userDao.login();
    }
}
@Test
    public void login() {
       ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.login();
    }

Bean的初始化方法和销毁方法

@PostConstruct //初始化 == init-method
@PreDestroy //销毁 == destory-method

@Component
public class liftBean {

    @PostConstruct   //初始化 == init-method
    public void aa(){
        System.out.println("我初始化了");
    }

    @PreDestroy   //销毁  == destory-method
    public void bb(){
        System.out.println("我over了");
    }
}
@Test
    public void login() {
       ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
       applicationContext.getBean("liftBean", liftBean.class);
       //手动关闭,才会销毁 
        ((ClassPathXmlApplicationContext)applicationContext).close();
    }

Bean的作用域

@Scope("singleton")//单例
@Scope("prototype")//多例

@Component
@Scope("singleton")//单例
@Scope("prototype")//多例
public class liftBean {

    @PostConstruct   //初始化 == init-method
    public void aa(){
        System.out.println("我初始化了");
    }

    @PreDestroy   //销毁  == destory-method
    public void bb(){
        System.out.println("我over了");
    }
}
@Test
    public void login() {
       ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        liftBean liftBean = applicationContext.getBean("liftBean", liftBean.class);
        liftBean liftBean2 = applicationContext.getBean("liftBean", liftBean.class);
        System.out.println(liftBean);
        System.out.println(liftBean2);

    }

XML和注解混合配置 (重点)

public class UserDaoImpl implements UserDao {
    @Override
    public void login() {
        System.out.println("dao层登录成功!!!");
    }
}
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    public void login() {
        System.out.println("业务层 登录!!!");
        userDao.login();
    }
}
<!--dao对象-->
    <bean id="userDao" class="cn.yanqi.dao.impl.UserDaoImpl"/>

    <!--service对象-->
    <bean id="userService" class="cn.yanqi.service.impl.UserServiceImpl"/>

    <!--开启注释
         扫描 @PostConstruct @PreDestroy @Autowired @Resource
    -->
    <context:annotation-config/>
@Test
    public void login() {
       ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.login();
    }
提示:因为采用注解开发时, <context:component-scan> 具有<context:annotation-config>的功能 。如果没有配置注解扫描,需要单独配置 <context:annotation-config>, 才能使用注解注入!

Xml配置文件名字问题

pring的核心配置文件名,是可以随便书写的,只要在加载时能加载到配置文件即可

Spring的junit测试集成

代码实现

Spring提供 spring-test.jar 可以整合junit。

好处:可以简化测试代码(不需要手动创建上下文)

<!--单元测试-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

<!--spring-test-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>5.2.9.RELEASE</version>
</dependency>

spring整合junit代码实现

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class UserServiceTest {

    //注入业务层
    @Autowired
    private UserService userService;

    @Test
    public void login() {
        /*ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);*/
        userService.login();
    }
}
@Service //直接注入不用再写对象名了
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    public void login() {
        System.out.println("业务层 登录!!!");

        userDao.login();
    }
}
@Repository //直接注入不用再写对象名了
public class UserDaoImpl implements UserDao {
    @Override
    public void login() {
        System.out.println("dao层登录成功!!!");
    }
}

评论需要登录。生产环境使用 GitHub 登录,本地可前往 登录页 使用开发登录。

还没有评论,来抢沙发。