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流程图
]()
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>