SpringFrameWork小总结

环境搭建

创建工程并且在maven里添加Spring依赖

<dependencies>
 <!-- Spring IOC最小依赖是beans、context,我们引入context依赖,maven会自动将其他依赖一并引入 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.8.RELEASE</version>
    </dependency>
</dependencies>

编写 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
     <!--开启注解支持-->
    <context:annotation-config/>
    <!--扫描路径包-->
    <context:component-scan base-package="SpringCoad" />
	<!--其他配置bean-->
</beans>
<!--这里做了错误演示https应该去掉s 否则ide运行会报错或则运行很慢或没网也不能运行-->

注意:我们有时会去网上粘贴xml摘要配置信息,idea运行时会报找不到文件错误需要把https改为http 就可以在idea运行了

org.xml.sax.SAXParseException; lineNumber: 10; columnNumber: 102; schema_reference.4: 无法读取方案文档 ‘https://www.springframework.org/schema/beans/spring-beans.xsd’, 原因为 1) 无法找到文档; 2) 无法读取文档; 3) 文档的根元素不是 xsd:schema。

https://www.springframework.org/schema/beans/spring-beans.xsd

//main方法
public static void main( String[] args ) {
    //用实现类接收上下文配置信息 方便调用registerShutdownHook()方法销毁连
        ApplicationContext ctx=new ClassPathXmlApplicationContext("classpath:applictionContext.xml");
//         ApplicationContext ctx=new ClassPathXmlApplicationContext("classpath*:applictionContext.xml");
//代表所有的applictionContext.xml文件
        //注册注解配置类
        	AnnotationConfigApplicationContext atx=new 					AnnotationConfigApplicationContext(App.class);
    //向JVM运行时注册一个关闭钩子
     ctx.registerShutdownHook();
 }

Spring控制反转(IOC)

IOC流程图

idea 2024 没有了 Spring Initializr_spring

]()

SpringIOC(Inversion of Control)是一个容器,也就是我们通常所说的控制反转。 IOC容器将我们的javabean和一些用于描述这些bean应该如何初始化、组装的配置信息进行整合。提供给我们开发人员一个配置、组装完成的上下文给我们使用,我们可以方便的通过IOC容器将繁杂的对象创建、管理工作托管给IOC容器。所以称之为控制反转。(由原来的开发人员自己控制对象的创建、组装改为交由Spring IOC容器负责)

配置元数据

配置元数据用于告诉SpringIOC容器,你的javabean应该怎么初始化、装配,以及它的生命周期(单例、原型等)。

配置元数据有xml和annotation两种方式。

Xml and Annotation

Spring3.0开始全面支持Java注解后,网上开始有很多人讨论到底哪种配置方式更好? 甚至有许多人觉得有了Annotation的方式,就可以完全替代以前的xml配置了。

其实这两种配置方式没有绝对的优劣,各自有适用的场景。我们一般在工作中会结合两者来使用。

XML配置方式
  • 优点:
    对代码没有任何侵入性, 改了配置不需要重新编译、打包
  • 缺点:
    配置相比注解的方式要繁琐很多,会导致配置文件有很多个bean
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="***" class="***">   
        <!-- id是个这类的标识 class是这个类的路径指向 -->
    </bean>
    <bean id="***" class="***">
       <!-- id是个这类的标识 class是这个类的路径指向 -->
    </bean>
    <!-- 后面可以写很多bean -->
</beans>

在一个配置文件中导入其他配置文件

<beans>
    <!-- 被导入的文件必须包含完整的beans根节点 -->
    <import resource="applicationContext.xml"/>
    <!-- 导入类路径下的resources目录下的messageSource.xml文件 -->
    <import resource="resources/applicationContext.xml"/>
    <!-- spring会忽略开头的/, 但是官方不建议路径以/开始,因为这里写的都是相对路径 -->
    <import resource="/resources/applicationContext.xml"/>
    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>
</beans>
常用注解Annotation
<context:annotation-config/>
<context:component-scan base-package="SpringCoad" />
@Bean

@Bean`注解允许我们通过注解的方式定义在Java代码中定义bean的配置元数据,相当于xml配置文件中的

@Configuration

@Configuration` 注解的类相当于xml配置文件中的

@Component

此注解是一个通用注解,代表一个组件,可以用来标识所有希望让Spring管理的bean。

@Required
用于标注在setter方法之上,表示此属性必须要注入。如果容器初始化该bean时没有合适的值注入到该属性则直接抛出异常。
@Autowired

根据依赖的类型自动注入。该注解可以用于标注在 属性、setter方法、构造方法、或带参数的普通方法之上。Spring会将符合的参数自动注入到属性、或方法参数中

@Configuration	// 类上面必须添加此注解,否则里面用@Bean配置无法使用自动注入其他参数(被称为"精简"bean“)
public class FactoryMethodComponent {
    private static int i;
    @Bean
    @Qualifier("public")	// 定义bean的标识符相当于xml方式给<bean>标签指定子标签<qualifier>
    public TestBean publicInstance() {
        return new TestBean("publicInstance");
    }
    // 自动注入特定bean方法参数,和普通字符串类型参数
    @Bean
    protected TestBean protectedInstance(
            @Qualifier("public") TestBean spouse,
            @Value("#{privateInstance.age}") String country) {
        TestBean tb = new TestBean("protectedInstance", 1);
        tb.setSpouse(spouse);
        tb.setCountry(country);
        return tb;
    }
  	// 指定生命周期init方法,相当于xml中给<bean>添加init-method属性
  	@Bean(initMethod = "init")
    public BeanOne beanOne() {
        return new BeanOne();
    }
  	// 指定生命周期destroy方法,相当于xml中给<bean>添加destroy-method属性
    @Bean(destroyMethod = "cleanup")
    public BeanTwo beanTwo() {
        return new BeanTwo();
    } 
	  //通过name属性指定bean的名称,相当于xml中给<bean>添加name属性
  	//如果不指定name属性,默认取值为方法名
    @Bean(name="testBean")	
    private TestBean privateInstance() {
        return new TestBean("privateInstance", i++);
    }
    @Bean
    @RequestScope// 指定scope, 相当于xml配置给<bean>添加scope属性
    public TestBean requestScopedInstance() {
        return new TestBean("requestScopedInstance", 3);
    }
}
@Scope

此注解可以限定通过注解配置的bean的作用域

@Configuration
public class MyConfiguration {
    @Bean
    @Scope("prototype")
    //Scope默认值为singleton(单例)
    public Encryptor encryptor() {
    }
}
@Resource

根据依赖bean的名称自动注入。除了可以通过Spring特有的@Autowired注解进行依赖注入外,Spring也支持原生JSR-250中的 @Resource注解。

public class SimpleMovieLister {
    private MovieFinder movieFinder;
    @Resource(name="myMovieFinder") 
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}

@Resource注解的name属性不是必须的,如果不指定,那默认的名称将取决于变量名称、setter方法的名称(取决于注解在变量上还是setter方法上)

@Resource注解还有个好处,如果按名称无法找到一个匹配bean的时候,它会自动按照类型查找注入。

@Primary

当我们通过@Autowired注解来注入属性或者参数时,如果遇到上面说的单值属性有多个匹配类型候选bean,如果其中一个候选Bean上配置了@Primary注解或者在xml配置中设置了primary=“true”,那将不会报错,Spring会优先将带primary标记的候选bean注入

@Qualifier

该注解可以让我们通过名称在多个候选bean中进一步限定。

public class MovieRecommender { @Autowired @Qualifier("main") private MovieCatalog movieCatalog; }

通过@Qualifier限定构造参数注入

public class MovieRecommender {
    private MovieCatalog movieCatalog;
    private CustomerPreferenceDao customerPreferenceDao;
    @Autowired
    public void prepare(@Qualifier("main") MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }
}
@ImportResource

通过注解的方式引入xml配置

示例:

@Configuration
@ImportResource("applicationContext.xml")
public class AppConfig {
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
    return new DriverManagerDataSource(url, username, password);
}
}

xml配置文件

<beans>
    <context:property-placeholder location="classpath:jdbc.properties"/>
</beans>

properties文件

jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=root
jdbc.password=root
@PropertySource

引入外部文件properties文件

//运用注解搭配使用可简化代码
@Configuration
@PropertySource("jdbc.properties")
public class JDBCconf {
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
@Bean("query")
public Object query(){
    return "url:"+url+"\n"+"driver:"+driver+"\n"+"username:"
            +username+"\n"+"password:"+password;
}
@Import

通过此注解引入其他类注解配置

@Import({MyConf.class})
//此处大括号里可以引入多个类 的配置
@Configuration
public class Application {

    @Bean
    public StudentService studentService() {
      return new StudentServiceImpl();
    }
}
@Configuration
public class MyConf {
    @Bean
    public StudentDao studentDao() {
      return new StudentDaoImpl();
    }
}
bean属性(name and id)
id属性:

id属性 通过注解的方式 也可以通过xml配置的方式 ,特点唯一

id属性注解演示如下:

@Configuration
public class MyConf {
    @Bean("testApple")
    //可以给id属性值,如不给则默认是@Bean对应下的法名
    public Fruit testApple(){
        return new Apple();
    }
}
//测试方法
public static void testbeanName(ApplicationContext ctx){
        Fruit fruit =ctx.getBean("testApple",Fruit.class);
        System.out.println(fruit);
    }
//运行结果:SpringCoad.littletest.Apple@1139b2f3
name属性:

name属性与id属性相似,特点属性值可以有多个。同时用xml配置也可以实现

<!--在xml里的配置-->
<bean id="student" name="stu1,stu2,stu3" class="SpringCoad.dao.Student">
    <constructor-arg name="name" value="张三"></constructor-arg>
    <constructor-arg name="nickname" value="阿三"></constructor-arg>
    <constructor-arg name="fruit" ref="apple"></constructor-arg>
</bean>
//测试方法 
public static void testbeanName(ApplicationContext ctx){
        Student stu=ctx.getBean("stu1",Student.class);
        System.out.print("爱称:"+stu.getNickname()+"  称号:"+stu.getName()+"  正在:");
        stu.getFruit().eatFruit();
    }
 //运行结果:爱称:阿三  称号:张三  正在:eating apple .....
bean的生命周期
public class hh {
    private void myInit() {
        System.out.println("大哥来了!");
    }
    private void myDestroy() {
        System.out.println("大哥慢走!");
    }
}

在xml里配置指定创建销毁方法,如果不设置加载模式(懒加载)程序一运行就会调用init方法,销毁方法需要设置一下【向JVM运行时注册一个关闭钩子
ctx.registerShutdownHook();】在jvm关闭时调用它

<bean id="hh" class="SpringCoad.dao.hh" init-method="myInit" destroy-method="myDestroy"/>
bean的作用域
<bean id="messageServiceimpo" class="SpringCoad.serivce.MessageServiceimpo" scope="singleton">
        <property name="messageDao" ref="MessageDao"></property>
    </bean>
<!--scope="值" 值为:singleton为单例 所获对象为同一个 值为:prototype为非单例 所获对象为不同的-->

这是xml配置的操作,注解也可以操作见@Scope注解

懒加载

(lazy-init=“true”[false/default])

xml配置方式通过default-lazy-init 统一指定,在bean定义时指定,与@lazy对应。当然也可以,@lazy可以直接用在@bean或@Component定义的类上,也可以使用在 @Configuration定义类上,后者表示该类中所有@Bean方法对应类被懒加载,与default-lazy-init 功能一致。

<!--统一指定 xml里配置-->
<beans http://www.springframework.org/schema/context/spring-context.xsd " default-lazy-init="true">
<!--在bean里指定 -->
 <bean id="test" class="SpringCoad.dao.testLazy" init-method="myInit" destroy-method="myDestroy" lazy-init="true"/>
注解导入xml配置

也就是用@Configuration注解的类导入xml配置

在这可新建一个类用于演示,用@Configuration注解此类

@Configuration // 加上此注解可将此类看成是一个配置文件
public class MyConf {

    @Bean("ap1") // 此注解作用相似与xml配置文件中的<bean id="ap1">写法
                //若是@Bean 不给值默认是smallBanana即<bean id="testBanana">
    public Fruit testBanana() {
        return new Banana();
    }   
}

在App.java中用将@Configuration注解的MyConf类、用注解方式导入xml配置

@Import(MyConf.class)//导入其他类的注解
@ImportResource("applicationContext.xml")//导入xml配置
Fruit fruit = ctx.getBean("ap1", Fruit.class);
System.out.println(fruit);
//其运行结果为:SpringCoad.dao.Apple@29176cc1
工厂模式

我对工厂的理解我给它一个值,它给我返回一个对象,且是批量的,我称之为工厂模式。[静态工厂/非静态工厂/构造方法]获得对象

<!--非静态工厂模式获取对象,需要依赖bean-->
 <bean id="fruit" class="SpringCoad.dao.FruitFactroy" />
    <bean id="banana" factory-bean="fruit" factory-method="unfactroy">
        <constructor-arg name="name" value="banana"/>
 </bean>
<!-- 静态工厂获取对象-->
<bean id="fruit1" class="SpringCoad.dao.FruitFactroy" factory-method="factroy">
        <constructor-arg name="name" value="apple"/>
</bean>
<!-- 无参构造函数获取对象-->
<bean id="fruit" class="SpringCoad.dao.FruitFactroy" />
public class FruitFactroy {
//测试静态的方法
    public static Fruit factroy(String name){
        switch(name){
            case "apple":
                return new Apple();
            case "banana":
                return new banana();
            default:
                return null;
        }
    }
    //测试非静态的方法
    public Fruit unfactroy(String name){
        switch(name){
            case "apple":
                return new Apple();
            case "banana":
                return new banana();
            default:
                return null;
        }
    }
}

DI(Inversion of Control)

DI,全称为Dependency Injection,即依赖注入。在Spring通过配置文件配置了依赖关系之后,可以通过多种方式对对象进行注入,比如说Service实现类中的方法需要依赖dao实现类,我们就能通过Spring配置文件写好注入配置,在使用时,我们只需要定义好dao接口,而不需要去获取它的实例,由Spring为我们注入。

注入内部类
<bean id="st" class="SpringCoad.dao.Student">
        <property name="fruit">
            <bean class="SpringCoad.dao.Apple" />
        </property>
    </bean>

测试方法

Student st = ctx.getBean("st", Student.class);
 st.getFruit().eatFruit();
//运行结果:eating Banana .....
注入集合类型属性
<!-- 注入集合、Map类型参数 -->
    <bean id="mylist" class="SpringCoad.dao.Mylist" >
        <!-- 注入List集合 -->
        <property name="hobbies">
            <list>
                <value>唱</value>
                <value>跳</value
            </list>
        </property>

        <!-- 注入Set集合 -->
        <property name="sex">
            <set>
                <value>男</value>
                <value>女</value>
            </set>
        </property>

        <!--注入map集合-->
        <property name="testMap">
            <map>
                <entry key="张三" value="三哥"></entry>
                <entry key="李四" value="四哥"></entry>
                <entry key="王二" value="二哥"></entry>
 <!-- 注入控制的方法
<entry key="张三" >  
                    <null />
                </entry>
                <entry key="李四" >
                <null />
                </entry>
                <entry key="王二" >
                <null />
                </entry>-->
            </map>
        </property>
        <!--注入properties-->
        <property name="nickName">
   <props>
       <prop key="张三">33</prop>
       <prop key="李四">44</prop>
   </props>
         </property>
    </bean>
注入null
<!-- 注入控制的方法-->
				<entry key="张三" >  
                    <null />
                </entry>
                <entry key="李四" >
                	<null />
                </entry>
                <entry key="王二" >
                	<null />
                </entry>
注入复合属性值
//演示通过student1给student2里的name属性赋值
@Setter
@Getter
public class Student1 {
    private int age;
    private Student2 Student;
}
@Setter
@Getter
public class Student2 {
    private String name;
}

xml里的配置

<bean id="stu1" class="SpringCoad.dao.Student1">
        <property name="Student" >
            <bean class="SpringCoad.dao.Student2"/>
        </property>
    <property name="student.name" value="大王"/>
    </bean>

测试方法

Student1 student1=ctx.getBean(Student1.class);
        System.out.println("Student2的name值:"+student1.getStudent().getName());
运行结果
Student2的name值:大王
注入外部properties文件中的属性值

建立实体类 用于存properties的值,

xml配置引入properties文件,

通过注解或者xml配置取出properties文件的值放入实体类中

//运用注解引入xml配置文件并运用注解的方法取jdbc文件设置的值
@Configuration
@ImportResource("applictionContext.xml")
public class JDBCconf {
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
@Bean("query")
public Object query(){
    return "url:"+url+"\n"+"driver:"+driver+"\n"+"username:"
            +username+"\n"+"password:"+password;
}
}
//引入jdbc配置文件location="classpath:jdbc.properties
<context:property-placeholder location="classpath:jdbc.properties"/>
//测试方法
public static void testjdbcFile(ApplicationContext ctx){
    Object myconf=ctx.getBean("query");
    System.out.println(myconf);
}
//运行结果
//  url:jdbc:mysql://localhost:3306/bookasp?charsetEncoding=utf8
//  driver:com.mysql.jdbc.Driver
//  username:root
//  password:root
<!--引入外部文件方式一-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="文件位置" />
</bean>
<!--引入外部文件方式二-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--外部文件取值方式一(参考以上java代码)-->
<!--外部文件取值方式二在xml配置文件里取值存入实体类-->
<bean id="jdbcConf" class="SpringCoad.dao.JDBCconf">
       <property name="url" value="${jdbc.url}" />
        <property name="driver" value="${jdbc.driver}" />
      <property name="username" value="${jdbc.username}" />
     <property name="password" value="${jdbc.password}" />
   </bean>-->
p and c注入
//通过c命名空间来注入 通过set
   <bean id="hh" class="SpringCoad.dao.bean.testStudent" c:sname="阿杰" />
//通过p命名空间来注入 通过构造参数
   <bean id="hh1" class="SpringCoad.dao.bean.testStudent" p:sname="阿杰1" />
       //普通注入参数
       //<bean id="hh2" class="SpringCoad.dao.bean.testStudent">
       // <property name="name" value="安吉尔" />
       //</bean>
      //想用p或c注入  必须要设置schema  xml配置摘要
       <bean  xmlns:p="http://www.springframework.org/schema/p" />
      <bean xmlns:c="http://www.springframework.org/schema/c" />
       
   public static void testStudent(ApplicationContext ctx) {
         testStudent stu = ctx.getBean("hh", testStudent.class);
        System.out.println("c注入,name: " + stu.getName());
 
        testStudent stu1 = ctx.getBean("hh1", testStudent.class);
        System.out.println("p注入, name: " +stu1.getName());
    }
//运行结果
//c注入,name: 阿杰
//p注入, name: 阿杰1
自动装配

通过名称自动注入

<!--通过name 需要保证Byname属性  也就是实列对象id不能重复 --><bean id="stuByName" class="SpringCoad.dao.Student1" 		autowire="byName">
  <property name="age" value="123" />
</bean>

通过类型自动注入

<!--通过name 需要保证类型的唯一,否者则会报错-->	<bean id="stuByType" class="SpringCoad.dao.Student1" autowire="byType">
   	<property name="age" value="123" />
</bean>

通过构造器自动注入

<!--构造器参数自动注入(按照类型)(容器中符合此类型的bean只能有一个,否则报错)--><bean id="stuByType" class="SpringCoad.dao.Student1"   autowire="constructor">
   	<property name="age" value="123" />
</bean>