美文网首页
一起来学习Spring:Spring入门与IOC篇

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

作者: __y | 来源:发表于2018-06-02 21:30 被阅读52次

    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指定了值,那么就根据名字来找

    相关文章

      网友评论

          本文标题:一起来学习Spring:Spring入门与IOC篇

          本文链接:https://www.haomeiwen.com/subject/fatajftx.html