Spring(一)

Spring(一)

控制反转

Inversion of Control,缩写为IoC,把创建对象的权利交给框架,是框架的重要特征,它包括依赖注入和依赖查找.

工厂模式解耦代码
/**
 *BeanFactory:一个创建Bean对象的工厂:
 *
 * Bean:在计算机英语中,有可重用组件的含义
 *JavaBean: 用java语言编写的可重用组件
 *      javabean != 实体类
 *      javabenan 的范围远大于实体类
 *
 *创建service和dao对象:
 *      第一:需要一个配置文件来配置service 和 dao
 *            配置的内容:唯一标识 = 全限定类名 (key=value) 去获取这个全限定类名
 *      第二:通过读取配置文件中配置的内容,反射创建对象
 *      配置文件可以是 xml 也可以是 properties
 *
     *      Properties(Java.util.Properties),
     *      该类主要用于读取Java的配置文件,
     *      不同的编程语言有自己所支持的配置文件,
     *      配置文件中很多变量是经常改变的,为了方便用户的配置,
     *      能让用户够脱离程序本身去修改相关的变量设置。
 *
 */



//去读取 resources中的 bean.properties文件
/*public class BeanFactory {
    //定义一个Properties对象
    private static Properties props;

    //使用静态代码块为Properties对象赋值
    static {
        //实例化对象
        props = new Properties();
        //获取properties文件的流对象  用类加载器去读这个文件
        InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        try {
            props.load(in);
        } catch (IOException e) {
            throw new ExceptionInInitializerError("初始化properties失败!");
        }
    }

    *//**
     * 根据Bean的名称获取bean对象
     *
     * @param beanName
     * @return
     *//*
    public static Object getBean(String beanName) {
        Object bean = null;
        String beanPath = props.getProperty(beanName);
        try {
            *//**
             * 用反射的方式来创建对象
             * 并且因为newInstance()  每次都会调用默认构造函数,
             * 导致每次都初始化创建对象,每次创建不同对象它是多例的
             * 因此需要解决(如下)!!!!
             *//*
            bean = Class.forName(beanPath).newInstance();
        } catch (Exception e) {
            e.printStackTrace();

        }
        return bean;
    }
}*/

//去读取 resources中的 bean.properties文件
public class BeanFactory {
    //定义一个Properties对象
    private static Properties props;
    //定义一个Map,用于存放我们需要创建的对象。我们把它称之为容器
    private static Map<String,Object> beans;

    //使用静态代码块为Properties对象赋值
    static {
        try {
            //实例化对象
            props = new Properties();
            //获取properties文件的流对象  用类加载器去读这个文件
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
                props.load(in);
            //实例化容器
            beans=new HashMap<String, Object>();
            //取出配置文件中所有的Key
            Enumeration keys = props.keys();//获得一个枚举类的keys
            //遍历枚举
            while(keys.hasMoreElements()){
            //取出每个key
                String key = keys.nextElement().toString();
            //根据key获取value
                String beanPath = props.getProperty(key);
            //反射创建对象
                Object value = Class.forName(beanPath).newInstance();
                //把key和value放入容器中
                beans.put(key,value);
                }
            } catch (Exception e) {
                    throw new ExceptionInInitializerError("初始化properties失败!");
            }

    }
    /**
     * 根据Bean的名称获取bean对象
     *此时已变成了单例的,都是同一个对象
     * @param beanName
     * @return
     */
    public static Object getBean(String beanName) {
        return beans.get(beanName);
    }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结

/** -------------总结----------------------------
 * AccountServiceImpl as = new AccountServiceImpl();
 * AccountServiceImpl as = (AccountServiceImpl) BeanFactory.getBean("accountService");
 * 这是两种截然不同的创建对象的方式
 *  第一种  是 new  app就是直接主动去找资源
 *  第二种是app通过联系工厂 去找资源 ,工厂去控制资源,并且工厂为app提供资源
 *而这就是IOC思想(控制反转)
 */

现在使用Spring 来进行解耦

1.1 什么是Spring

Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。

1.2 Spring的优点
  • 方便解耦,简化开发 (高内聚低耦合)
    Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理
    spring工厂是用于生成bean
  • AOP编程的支持
    Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
  • 声明式事务的支持
    只需要通过配置就可以完成对事务的管理,而无需手动编程
  • 方便程序的测试
    Spring对Junit4支持,可以通过注解方便的测试Spring程序
  • 方便集成各种优秀框架
    Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
  • 降低JavaEE API的使用难度
    Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
1.3 Spring的体系结构

在这里插入图片描述

入门案例

配置文件

bean.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 id= "accountService" class= "x.xss.service.impl.AccountServiceImpl"></bean>

    <bean id="accountDao" class="x.xss.dao.impl.AccountDaoImpl"></bean>
</beans>

表现层

/**
 * 模拟一个表现层,用于调用业务层
 */
public class Client {
    /**
     * 获取spring的Ioc容器,并根据id获取对象
     *
     * ApplicationContext的三个常用实现类:
     *
     *     ClassPathXmlApplicationContext : 它可以加载类路径下的配置文件,
     *                                      要求配置文件必须在类路径下。
     *                                      不在的话,加载不了。也就无法获
     *                                      取核心容器对象
     *
     *     FileSystemXmlApplicationContext : 它可以加载磁盘任意路径下的配置文件
     *                                          (必须有访问权限)
     *     AnnotationConfigApplicationContext : 它是用于读取注解创建容器的。
     *
     * 核心容器的两个接口引发的问题   bean对象的创建默认是单例的
     * 1, ApplicationContext: 单例对象适应  (实际开发中更多使用此接口)
     *      它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。
     *    也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。
     *
     *,2, BeanFactory;  多例对象适用
     *      它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。
     *     也就是说,什么时候根据id获取对象了,就什么时候才创建真正的对象。
     *
     *
     * @param args
     */
    public static void main(String[] args) {
        //1,获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\Users\\2019\\IdeaProjects\\day722_03spring\\src\\main\\resources\\bean.xml");
        //2,根据id获取Bean对象
            //两种方式 ,强转,或者是输入字节码文件强转
        AccountService as = (AccountService) ac.getBean("accountService");
        AccountDao adao = ac.getBean("accountDao", AccountDao.class);
        System.out.println(as);
        System.out.println(adao);
        // as.saveAccount();


       /*
       //------- BeanFactory 创建对象,创建的bean是多例的----------
        Resource resource = new ClassPathResource("bean.xml");
        BeanFactory factory = new XmlBeanFactory(resource);
        AccountService as = (AccountService)factory.getBean("accountService");
        System.out.println(as);
        */
    }
}
spring 中工厂的类结构图

在这里插入图片描述

在这里插入图片描述

BeanFactory 和 ApplicationContext 的区别

​ BeanFactory 才是 Spring 容器中的顶层接口。 ApplicationContext 是它的子接口。 BeanFactory 和 ApplicationContext 的区别: 创建对象的时间点不一样。 ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。 BeanFactory:什么使用什么时候创建对象。

ApplicationContext 接口的实现类

ClassPathXmlApplicationContext: 它是从类的根路径下加载配置文件 推荐使用这种 FileSystemXmlApplicationContext: 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。 AnnotationConfigApplicationContext: 当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。

Spring对Bean 的管理细节

bean 标签

作用:

​ 用于配置对象让 spring 来创建的。

​ 默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。

属性

id:给对象在容器中提供一个唯一标识。用于获取对象。

class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。

scope:指定对象的作用范围。

​ singleton :默认值,单例的.

​ prototype :多例的.

​ request : WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.

​ session : WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.

​ global session :WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么 globalSession 相当于 session.

​ init-method:指定类中的初始化方法名称。

​ destroy-method:指定类中销毁方法名称。

1,创建bean的三种方式
方式一 :使用默认构造函数创建。

在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性标签时。
采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建

/*配置文件中
*/
<bean id= "accountService" class= "x.xss.service.impl.AccountServiceImpl"></bean>   

//实现类中
    public class AccountServiceImpl implements AccountService {
	//默认构造函数
   public AccountServiceImpl() {
       System.out.println("对象被创建了");
    	}
    }
方式二 别人写好的类,存在jar包中

使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)

/**
 * 模拟一个工厂类(此类可能存在于jar包中,
 * 我们无法通过修改源码的方式来提供默认构造函数
 */
public class InstanceFactory {
    public AccountService getAccountServive(){
        return new AccountServiceImpl();
    }
}
<!-- 此种方式是:
先把工厂的创建交给 spring 来管理。
然后在使用工厂的 bean 来调用里面的方法
factory-bean 属性:用于指定实例工厂 bean 的 id。
factory-method 属性:用于指定实例工厂中创建对象的方法。
-->
<bean id="instanceFactory" class="x.xss.factory.InstanceFactory"></bean>
   <!--accountService的创建不再自己创建了,而是去使用 nstanceFactory,所以加上下面的配置-->
<bean id="accountService" 
      factory-bean="instanceFactory"  <--找到此类中的-->
      factory-method="getAccountServive"> <--此方法-->
</bean>
方式三 别人写好的类,存在jar包中

使用工厂中的静态方式创建对象(使用某个类中的静态方法创建对象,并存入spring容器)

/**
 * 模拟一个工厂类(此类可能存在于jar包中,
 * 我们无法通过修改源码的方式来提供默认构造函数
 * 这里是静态的方法
 */
public class StaticFactory {
    public static AccountService getAccountServive(){
        return new AccountServiceImpl();
    }
}
<!--使用 StaticFactory 类中的静态方法 createAccountService 创建对象,并存入 spring 容器
id 属性:指定 bean 的 id,用于从容器中获取
class 属性:指定静态工厂的全限定类名
factory-method 属性:指定生产对象的静态方法-->
<bean id="accountService" 
      class="x.xss.factory.StaticFactory" 
      factory-method="getAccountServive">
</bean>
2,bean对象的作用范围

默认是单例的
bean标签的scope属性;
作用: 用于指定bean的作用范围
取值:
singleton : 单例的(也是默认值)(常用)
prototype : 多例的 (常用)
request : 作用于web应用的 请求 范围
session : 作用于web应用的 会话 范围
global-session: 作用于 集群环境的会话范围(全局会话范围)
,当不是集群环境时,就是session

<bean id= "accountService" class= "x.xss.service.impl.AccountServiceImpl"
scope="singleton" init-method="init" destroy-method="destory"></bean>
3,bean对象的生命周期

单例对象
出生 容器创建时,对象出生
活着
死亡 容器销毁时,对象消亡
总结:单例对象的生命周期与容器相同
多例对象
出生 当使用对象时,spring框架会创建
活着 对象在使用过程中 bean就一直存在
死亡 当对象长时间不用,且没有别的对象引用时,
·有java的垃圾回收器回收

spring 的依赖注入

依赖注入:
Dependency Injection
IOC的作用:
降低程序间的耦合(依赖关系)
依赖关系的管理:
以后都交给了spring维护
在当前类中需要用到其他类的对象,由spring来提供,我们只需在配置文件中说明
依赖关系的维护:
称之为:依赖注入
依赖注入:
能注入的数据有三类
基本类型和String
其它bean类型(在配置文件中或者注解配置过的bean)
复杂类型/集合类型
注入的方式:有三种
第一种:使用构造函数提供
第二种: 使用set方法提供
第三种: 使用注解提供

1,构造函数的注入

​ 使用标签: constructor-arg
​ 标签出现的位置: bean 标签的内部
​ 标签中的属性 :
​ type :用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型(不能独立实现注入的功能)

​ index: 用于指定要注入的数据给构造函数中指定索引位置的参数赋值。参数索引的位置从0开始。

name: 用于指定给构造函数中指定名称的参数赋值 (常用的)

=以上三个用于指定给构造函数中的哪个参数赋值===

​ value: 用于提供基本类型和String类型的数据
​ ref : 用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象。
​ 例如出现过的bean对象:

优势:
​ 在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。
劣势:
​ 改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,
​ 也还是要提供。


    <bean id= "accountService" class= "x.xss.service.impl.AccountServiceImpl">
        <constructor-arg name="aaa" value="小明"></constructor-arg>
        <constructor-arg name="bbb" value="18"></constructor-arg>
        <constructor-arg name="ccc" ref="now"></constructor-arg>
    </bean>
    <!--配置一个日期对象-->
        <bean id="now" class="java.util.Date"></bean>
/**
 * 账户的业务层实现类
 */
public class AccountServiceImpl implements AccountService {

//如果是经常变化的数据,并不适用于注入的方式
     private String aaa;
     private Integer bbb;
     private Date ccc;
     //构造方法
    public AccountServiceImpl(String aaa, Integer bbb, Date ccc) {
        this.aaa = aaa;
        this.bbb = bbb;
        this.ccc = ccc;
    }
    public void saveAccount() {
       System.out.println("service中的saveAccount方法被执行了..."+ aaa + "," + bbb + "," + ccc);
   }
}
2, set方法注入

​ 涉及的标签:property
​ 出现的位置:bean标签的内部
​ 标签的属性
​ name:用于指定注入时所调用的set方法名称
​ value:用于提供基本类型和String类型的数据
​ ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
优势
​ 创建对象时没有明确的限制,可以直接使用默认构造函数
弊端:
​ 如果有某个成员必须有值,则获取对象时有可能set方法没有执行。

<bean id= "accountService2" class= "x.xss.service.impl.AccountServiceImpl2">
    <property name="aaa" value="小红"></property>
    <property name="bbb" value="15"></property>
    <property name="ccc" ref="now"></property>
</bean>
/**
 * 账户的业务层实现类
 */
public class AccountServiceImpl2 implements AccountService {

//如果是经常变化的数据,并不适用于注入的方式
     private String aaa;
     private Integer bbb;
     private Date ccc;
//set方法
    public void setAaa(String aaa) {
        this.aaa = aaa;
    }

    public void setBbb(Integer bbb) {
        this.bbb = bbb;
    }

    public void setCcc(Date ccc) {
        this.ccc = ccc;
    }

    public void saveAccount() {
       System.out.println("service中的saveAccount方法被执行了..."+ aaa + "," + bbb + "," + ccc);
   }

}
3,复杂类型的注入/集合类型的注入(实际开发中常用!!!)

​ 用于给List结构集合注入的标签:
​ list array set
​ 用于个Map结构集合注入的标签:
​ map props
​ 结构相同,标签可以互换

<bean id="accountService3" class="x.xss.service.impl.AccountServiceImpl3">
    <property name="a">
        <set>
            <value>数组1</value>
            <value>数组2</value>
            <value>数组3</value>
        </set>
    </property>

    <property name="b">
        <array>
            <value>List1</value>
            <value>List2</value>
            <value>List3</value>
        </array>
    </property>

    <property name="c">
        <set>
            <value>Set1</value>
            <value>Set2</value>
            <value>Set3</value>
        </set>
    </property>

    
    <property name="d">
        <props>
            <prop key="map1">m111</prop>
            <prop key="map2">m222</prop>
        </props>
    </property>

    
    <property name="e">
        <map>
            <entry key="写法1" value="Properties1111"></entry>
            <entry key="写法2">
                <value>Properties2222</value>
            </entry>
        </map>
    </property>
    
</bean>
/**
 * 账户的业务层实现类
 */
public class AccountServiceImpl3 implements AccountService {
    private String[] a;
    private List<String> b;
    private Set<String> c;
    private Map<String,String>d;
    private Properties e;

    //set 方法
    public void setA(String[] a) {
        this.a = a;
    }

    public void setB(List<String> b) {
        this.b = b;
    }

    public void setC(Set<String> c) {
        this.c = c;
    }

    public void setD(Map<String, String> d) {
        this.d = d;
    }

    public void setE(Properties e) {
        this.e = e;
    }

    public void saveAccount() {
        System.out.println(Arrays.toString(a));
        System.out.println(b);
        System.out.println(c);
        System.out.println(d);
        System.out.println(e);
   }

}
g,String>d;
    private Properties e;

    //set 方法
    public void setA(String[] a) {
        this.a = a;
    }

    public void setB(List<String> b) {
        this.b = b;
    }

    public void setC(Set<String> c) {
        this.c = c;
    }

    public void setD(Map<String, String> d) {
        this.d = d;
    }

    public void setE(Properties e) {
        this.e = e;
    }

    public void saveAccount() {
        System.out.println(Arrays.toString(a));
        System.out.println(b);
        System.out.println(c);
        System.out.println(d);
        System.out.println(e);
   }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值