一起来学习Spring:Spring入门与IOC篇

1.Spring的基本介绍

spring:从翻译来说是春天的意思,意思是给软件开发带来了春天(想象下春天的美好~),spring的作者的初衷是让现有的技术更加实用,不是创造轮子,而是使轮子更好的运转。他就是一个大杂烩,整合了现有的技术

spring的优点

1.轻量级框架,不具有侵入性,方便框架的整合;
2.IOC容器:控制反转;
3.AOP:面向切面编程;
4.对事务的支持;

spring的主要内容

image.png
  • Test:spring支持Junit单元测试
  • 核心容器(IOC):Bean(Bean工厂,创建对象),Core(核心,一切的基础),Context(上下文),SpEL(spring的表达式语言)
  • AOP:面向切面编程
  • 对数据访问的支持:jdbc,ORM(Mybatis等),Transaction(事务的管理),JMS(java邮件服务)
  • Web:Spring MVC

2. IOC(Inversion of Control 控制反转)

下面用代码的形式看一下IOC的设计思想
创建对象由spring来创建,装配
DAO层:


public interface UserDao {
    public void getUser();
}

DAO层的实现层:
我们现在有一个实现DAO层的类,是Mysql的

public class UserDaoMysqlImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("获取----Mysql");
    }
}

Oracle的

public class UserDaoMysqlImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("获取----Mysql");
    }
}

service的接口层,定义接口,通过DAO层取=数据

public interface UserService {
    public void getUser();
}

service的实现层:

import dao.UserDao;
import daoimpl.UserDaoMysqlImpl;//可以去掉了
import service.UserService;

public class UserServiceImpl implements UserService {
    //自己创建的对象,现在获取的是Mysql,后面如果我想要换成Oracle的时候就要改代码
    //后面涉及到的代码越来越多的话,耦合性越来越大
    //private UserDao userDao = new UserDaoMysqlImpl();

    //进一步修改代码
    private UserDao userDao = null;
    //对外提供一个设置的方法
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    @Override
    public void getUser() {
        userDao.getUser();
    }
}

Test(相当于客户端)

public class Test {
    public static void main(String[] args) {
        //在这里创建对象

        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(new UserDaoMysqlImpl());
        userService.getUser();
    }
}

分析:
1.我们可以看一下private UserDao userDao = new UserDaoMysqlImpl();这条语句是我们手动new出来的,这时候我们可以通过userDao这个对象去调用对应的方法。这没问题,但是如果以后我要改成Oracle,后面涉及到的代码越来越多的话,耦合性越来越大。 这样我们要改的代码就会很多,这是不利于我们后面的代码维护的。
2.我们看进一步修改后的代码,我们对外提供一个接口setUserDao方法来设置userDao,这样看起来是不是不管我们以后要改成什么Oracle还是Mysql,只要是实现Dao方法的传进来一个对象可以了。
3.我们再观察Test类,Test类就相当于客户端,UserServiceImpl就相当于应用程序了,应用程序不用再自己new对象,完全是将new对象的这个步骤交给了Test类(客户端),在由必要的时候才在客户端new一个对象。现在看起来还是我们手动的,但是如果我们将这些交给配置文件,我们就省了这一步功夫了。
通过上面的例子,我们可以得出IOC的好处:

  • 对象原来是程序本身创建的,变成了程序接收对象;
  • 我们在开发的时候可以更加地注重业务的开发
  • 实现了service和dao层的解耦工作,没有直接的依赖关系(举个简单的例子,我们可以把包含UserDaoMysqlImpl这个类的包名去掉了)

3.SpringIOC实现

我们在http://repo.springsource.org/libs-release-local/org/springframework/spring中下载对应的jar包


这里插入一个知识点:
IOC和DI(依赖注入,Dependency Injection)的区别
1.IOC:是把对象的创建交给Spring管理,由SpringIOC容器来创建对象,管理依赖关系
2.DI:依赖注入,在创建对象的过程中,向类里面的属性设置值
3.IOC和DI关系:依赖注入不能单独存在,必须在控制反转的基础上完成,就是注入类里面的属性值,不能直接注入,必须创建类的对象再完成注入


1.导入相关的jar包

image.png

2.创建配置文件和相关的实体类

public class Hello {
    private String name;

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

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 id = "hello" class="com.spring.test.Hello">
        <property name="name" value="Spring的使用者"></property>
    </bean>
</beans>

创建一个测试类

package test;

import com.spring.test.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestBean {
    public static void main(String[] args) {
      //加载spring的配置文件,将配置文件中的对象进行创建
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
      //根据配置文件的id获得Hello对象
        Hello hello = (Hello)applicationContext.getBean("hello");
        hello.show();
    }
}

结果:


image.png

4.Spring的bean管理

上面我们已经看到了基本的实现,下面我们来详细介绍一下bean的管理,有两种方式

  • 使用配置文件方式实现(如上文)
  • 使用注解的方式

Spring实例化bean的三种方式:

1.通过无参构造方法
2.通过有参构造方法
3.通过工厂模式:

  • 工厂静态
  • 工厂非静态
    上文已经展示了无参构造方法了,下面重点介绍剩下的两种

通过有参构造方法

首先我们看看实体类(必须有带参数的构造方法)

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

    public User(int id,String  name) {
        this.id = id;
        this.name = name;
    }

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

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }
}

bean配置

<bean id = "user" class="com.spring.test.User">
        <constructor-arg index="0" name = "id"  value="1"></constructor-arg>
        <constructor-arg index="1" name = "name" value="大帅比"></constructor-arg>
    </bean>

测试类:

public class TestBean {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        User user = (User)applicationContext.getBean("user");
        System.out.println(user.getId() + " " + user.getName());
    }
}

image.png

PS:
在constructor如果构造函数的值是一个对象,而不是一个普通的类型的值,我们就需要用到ref属性,而不是value属性
比如说
我在User对象上维护了Address对象的值,想要在构造函数中初始化

   <bean id = "address" class="Address"></bean>
bean id = "user" class="com.spring.test.User">
        <constructor-arg index="0" name = "id"  value="1"></constructor-arg>
        <constructor-arg index="1" name = "address"  ref = "address"></constructor-arg>
    </bean>

工厂静态方法

写一个Factory

public class Factory {
    public static  User getBean() {
        return new User();
    }
}

 <bean id = "user" class="com.spring.test.Factory" factory-method="getBean"></bean>
image.png

工厂非静态方法

public class Factory {
    public   User getBean() {
        return new User();
    }
}
   <bean id="factory" class="com.spring.test.Factory"></bean>
    <bean id = "user"  factory-bean="factory" factory-method="getBean"></bean>

装载集合(setter注入,要有set方法)

如果对象上的属性或者构造函数具有集合的时候,我们又要为其赋值,可以通过以下赋值:
在构造函数中

 <bean id = "user"   class="com.spring.test.User">
        <constructor-arg>
            <list>
                //基本类型
                <value></value>
            </list>
        </constructor-arg>
    </bean>

在属性上

<bean id = "user"   class="com.spring.test.User">
        <property name="name">
            <list>
                //引用类型
                <ref></ref>
            </list>
        </property>
    </bean>

5.Spring配置文件中bean标签中的属性讲解

  • id:唯一的标志,只能唯一
  • class属性:要创建的对象的全路径
  • scope:bean的作用范围
    1.singleton:创建的对象是单例的,也是scope属性的默认值
    2.prototype:创建的对象是多例的
    3.globalSession:用在单点登录上即(SSO,single sign on)

6.注解的方式使用bean

上面我们可以的看到,如果我们的Bean不断增加的话,bean配置会越来越多,自己也会越来越乱,这个时候我们推荐使用注解的方式来优化我们的编码过程

1.引入context命名空间

xmlns:context="http://www.springframework.org/schema/context"

2.开启注解扫描器

 <context-:component-scan base-package="com.spring"></context-:component-scan>

3使用Repository注解

//把对象添加到容器中,首字母会小写
@Repository("userDao")
public class UserDaoMysqlImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("获取----Mysql");
    }
}

4.使用Service注解

//把UserService对象添加到IOC容器中,首字母会小写
@Service("userService")
public class UserServiceImpl implements UserService {

    //如果@Resource不指定值,那么就根据类型来找--->UserDao....当然了,IOC容器不能有两个UserDao类型的对象
    //@Resource

    //如果指定了值,那么Spring就在IOC容器找有没有id为userDao的对象。
    @Resource(name = "userDao")
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    @Override
    public void getUser() {
        userDao.getUser();
    }
}

5.使用Controller注解

@Controller
public class Test {
    @Resource(name = "userService")
    private UserService userService;
    public static void main(String[] args) {
        //在这里创建对象
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        UserService userService  = (UserService) applicationContext.getBean("userService");
        userService.getUser();
    }
}

常用注解:

  • @ComponentScan扫描器

  • @Configuration表明该类是配置类

  • @Component 指定把一个对象加入IOC容器--->@Name也可以实现相同的效果【一般少用】

  • @Repository 作用同@Component; 在持久层使用

  • @Service 作用同@Component; 在业务逻辑层使用

  • @Controller 作用同@Component; 在控制层使用

  • @Resource 依赖关系

如果@Resource不指定值,那么就根据类型来找,相同的类型在IOC容器中不能有两个

如果@Resource指定了值,那么就根据名字来找

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容

  • 1.1 spring IoC容器和beans的简介 Spring 框架的最核心基础的功能是IoC(控制反转)容器,...
    simoscode阅读 6,709评论 2 22
  • 什么是Spring Spring是一个开源的Java EE开发框架。Spring框架的核心功能可以应用在任何Jav...
    jemmm阅读 16,460评论 1 133
  • 来源:关于Spring IOC (DI-依赖注入)你需要知道的一切作者:zejian Dao层(AccountDa...
    杨井阅读 5,333评论 0 27
  • 前言 前面已经学习了Struts2和Hibernate框架了。接下来学习的是Spring框架...本博文主要是引入...
    Java3y阅读 29,086评论 3 36
  • 有时候,一碟海带丝就能满足胃的所有需求 也不能说是海带丝,因为毕竟只比筷子细一点了。 墨绿晶莹,像一堆积在黑暗丛林...
    牧羊Max阅读 537评论 3 2