24.12.20 Spring

发布于:2024-12-21 ⋅ 阅读:(15) ⋅ 点赞:(0)
      • 极可能让类与类之间的关联降到最低
    • 原则
      • 责任单一原则
        • 需要用整个编程生涯来贯彻
      • 最少知道原则
        • 禁止跨级调用
        • 让一个类,认识/调用 最少的类
  • 简化事务
    • 事务:添加修改删除,出错了,回滚
    • 仅仅使用一个注解,就能让事务生效
  • 集成了JUnit,方便测试
  • 简化了开发
  • 方便集成各种框架
    • 使用Spring去管理所有的框架

控制反转(IOC)

正常情况下,对象的控制器,在程序员手中

反转了,交出了控制权,不再是每次使用对象的时候亲自new对象,而是交给了Spring容器去new对象,每次使用对象的时候,问Spring要

bean对象装到容器中

创建Spring项目

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.9.RELEASE</version>
  </dependency>
 </dependencies>
  • 依赖导入成功之后,创建配置文件
  • 管理bean(都要有set方法)
<?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">

    <!--当前的Student类交给了Spring容器去创建-->
    <bean id="abc" class="com.javasm.demo.Student"/>

</beans>
  • 测试类
private static void test1() {
        //从类加载路径中,加载配置文件spring1.xml
        //读取配置文件中的内容
        //解析xml标签
        //创建一个bean的集合,new一个对象,存入bean的集合等待调用
        //applicationContext 实际上就是Spring容器对象
        //不论是否调用bean对象,在Spring容器初始化的时候,都会创建bean对象
        ClassPathXmlApplicationContext applicationContext  =
                new ClassPathXmlApplicationContext("spring1.xml");
        //从Spring容器中,寻找id=abc的bean对象
        Student abc = (Student) applicationContext.getBean("abc");
        //赋值
        abc.setId(100);
        abc.setName("张三");
        abc.setAge(11);
        System.out.println(abc);
    }

启动原理

程序启动 → 读取xml文件 → 解析xml配置文件 → 读取了bean标签的内容 → 通过反射,初始化bean对象(new对象) → bean对象 存入Spring容器,等待调用

private static void test4() throws Exception{
        Student abc = (Student) test3("abc");
        //赋值
        abc.setId(100);
        abc.setName("张三");
        abc.setAge(11);
        System.out.println(abc);
    }

    //获取bean对象
    private static Object test3(String id)  throws Exception {
        Map<String, Object> map = test2();
        Object o = map.get(id);
        return o;
    }

    private static Map<String,Object> test2() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //<bean id="abc" class="com.javasm.demo.Student"/>
        String id = "abc";
        String className = "com.javasm.demo.Student";
        //通过反射,new对象
        Class<?> aClass = Class.forName(className);
        //bean对象
        Object o = aClass.getConstructor().newInstance();
        //创建一个容器
        Map<String,Object> springApplication = new ConcurrentHashMap<>();
        springApplication.put(id,o);
        return springApplication;
    }

获取Bean的方式

//根据id获取bean
Student abc = (Student) context.getBean("abc");
//根据类型获取
Student student = context.getBean(Student.class);
//根据ID +类型
Student abc1 = context.getBean("abc", Student.class);

别名

<!--别名,不常用-->
    <alias name="stu" alias="s"/>

Student s = context.getBean("s", Student.class);

创建Bean的方式

  • 无参构造

<bean id="abc" class="com.javasm.demo.Student"/>

  • 静态工厂
<bean id="xiaoming" class="com.javasm.demo.StudentStaticFactory" factory-method="getStudent"/>
public class StudentStaticFactory {
    public static Student getStudent(){
        Student student = new Student();
        student.setName("小明");
        return student;
    }
}
  • 实例工厂
<bean id="stuFactory" class="com.javasm.demo.StudentFactory"/>
    <bean id="xiaohong" factory-bean="stuFactory" factory-method="getStudent"/>
public class StudentFactory {
    public Student getStudent(){
        Student student = new Student();
        student.setName("小红");
        return student;
    }
}
  • Spring工厂
<!--Spring工厂-->
<bean id="huowang" class="com.javasm.demo.StudentSpringFactory"/>
public class StudentSpringFactory implements FactoryBean<Student> {
    @Override
    public Student getObject() throws Exception {
        //返回的对象是什么,Spring容器中存什么
        Student student = new Student();
        student.setName("李火旺");

        return student;
    }

    @Override
    public Class<?> getObjectType() {
        return Student.class;
    }

    @Override
    public boolean isSingleton() {
        //是否是单例
        //true:单例
        //false:多例
        //默认是true
        return true;
    }
}

单例

Spring的bean对象,在默认情况下,都是单例的

加上scope="prototype"将不是单例

<bean id="teacher" class="com.javasm.demo.Teacher" scope="prototype"/>

单例:Spring启动 → 加载解析XML文件 → 创建Bean对象 →bean保存到容器 →随着容器关闭销毁

多例:Spring启动→加载解析XML文件→先把解析的内容记录下来→调用的时候创建bean

懒加载

不使用不创建对象

仅仅对单例生效

<bean id="teacher1" class="com.javasm.demo.Teacher" lazy-init="true"/>

全局配置

<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"
        default-lazy-init="true"
>

初始化&销毁

<bean id="teacher2" class="com.javasm.demo.Teacher" init-method="test1" destroy-method="test2"/>

test1 和 test2 是普通的方法

构造方法
初始化方法
正常调用方法
---销毁
关闭容器

依赖注入(DI)

以来的对象,从Spring容器中获取,而非自己new

  • 测试类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Game {
    private Integer id;
    private String name;
    private Double price;
    //公司
    private Company company;
    //英雄列表
    private String[] heros;
    //关卡
    private List<String> levels;
    //背包
    private Map<Integer,String> items;
    //成就
    private Set<String> achievements;//不包含重复元素
    //游戏配置
    private Properties gameConfig;

    //玩家列表
    private List<Player> playerList;

}
@Data
public class Company {
    private String name;
    private String address;
}
@Data
public class Player {
    private Integer id;
    private String nickname;
}
<?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="game" class="com.javasm.demo2.Game">
        <property name="id" value="1000"/>
        <property name="name" value="黑悟空"/>
        <property name="price" value="648.88"/>
        <!--公司-->
        <property name="company" ref="company"/>
        <!--影响列表-->
        <property name="heros">
            <array>
                <value>孙悟空</value>
                <value>杨戬</value>
                <value>哪吒</value>
            </array>
        </property>
        <!--关卡-->
        <property name="levels">
            <list>
                <value>黑风寨</value>
                <value>黄风岭</value>
                <value>小西天</value>
            </list>
        </property>
        <!--背包-->
        <property name="items">
            <map>
                <entry key="1001" value="金箍棒"/>
                <entry key="1002" value="三尖两刃刀"/>
                <entry key="1003" value="定风珠"/>
            </map>
        </property>
        <!--成就-->
        <property name="achievements">
            <set>
                <value>借刀杀人</value>
                <value>顺手牵羊</value>
                <value>万箭齐发</value>
            </set>
        </property>
        <!--配置-->
        <property name="gameConfig">
            <props>
                <prop key="location">zh</prop>
                <prop key="model">全屏</prop>
            </props>
        </property>
        <property name="playerList">
            <list>
                <bean class="com.javasm.demo2.Player">
                    <property name="id" value="1001"/>
                    <property name="nickname" value="泉水指挥官"/>
                </bean>
                <ref bean="xiaoheizi"/>
            </list>
        </property>
    </bean>
    <bean id="company" class="com.javasm.demo2.Company">
        <property name="name" value="游戏科学"/>
        <property name="address" value="郑州863软件园"/>
    </bean>
    <bean id="xiaoheizi" class="com.javasm.demo2.Player">
        <property name="id" value="1002"/>
        <property name="nickname" value="小黑子"/>
    </bean>
</beans>

自动装配

<!--autowire 自动装配: byType、 根据属性的类型,去Spring容器中寻找对应的bean对象,如果找到了,自动赋值给对应的属性-->
    <bean id="g2" class="com.javasm.demo2.Game" autowire="byType"/>
    <!--根据属性的名字,去寻找id和属性名一样的bean,属性名称为类的私有变量名-->
    <bean id="g3" class="com.javasm.demo2.Game" autowire="byName"/>

全局

<?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"
    default-autowire="byName"
>

构造方法的注入

<?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="company" class="com.javasm.demo2.Company">
<property name="name" value="尚马"/>
</bean>
<!--
index:构造方法第几个参数
name: 构造方法的参数名称
推荐使用index配置参数
-->
<bean id="music" class="com.javasm.demo3.Music">
<constructor-arg value="100" name="id" type="java.lang.Integer"/>
<constructor-arg index="1" value="云顶天宫"/>
<constructor-arg index="2" value="10分钟"/>
<constructor-arg index="3" ref="company"/>
</bean>

</beans>
@Data
public class Music {

    public Music() {
    }

    public Music(Integer id, String name, String time, Company company) {
        this.id = id;
        this.name = name;
        this.time = time;
        this.company = company;
    }

    private Integer id;
    private String name;
    private String time;
    private Company company;
}

异常

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'abcd' available
bean的id写错了,没有找到名字是abcd的bean对象
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.javasm.demo.Student' available: expected single matching bean but found 2: abc,stu

根据类型,从Spring容器中获取bean对象,但是容器中有两个bean对象,是相同类型的,所以报错
因为我要找1个bean,但是发现了2个
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'teacher' defined in class path resource [spring1.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.javasm.demo.Teacher]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.javasm.demo.Teacher.<init>()
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'teacher' defined in class path resource [spring1.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.javasm.demo.Teacher]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.javasm.demo.Teacher.<init>()

因为类中没有无参构造,报错
养成一个习惯,只要写有参构造,不论是否需要无参构造,都要写一个