主要是对代码进行解耦和。
简介
spring源码是graddle构建
springframework 是spring 里面的一个基础开源框架,主要用于javaee的企业开发。Spring是什么呢?首先它是一个开源的项目,而且非常活跃;它是一个基于IOC和AOP构架的多层j2ee系统框架,但它不强迫你必须在每一层中必须使用Spring,因为它模块化的很好,允许你根据自己的需要选择使用它的某一个模块;它实现了很优雅的MVC,对不同的数据访问技术提供了统一的接口,采用IOC使得可以很容易的实现bean(普通的java类可以称为一个javaBean)的装配,提供了简洁的AOP(通过 创建代理对象实现对目标对象的功能扩展)并据此实现Transaction Management
full-stack :一站式开源框架。在web项目的各层都提供了解决方案
Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
Spring是一个一站式的轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。(单例)
控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。
面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。
spring版本
-
3.x
支持java5
-
4.x
支持java8
-
5.x
去除java9依赖,支持高版本java
spring相关下载
版本:release snapshot
-
Spring体系架构
spring提供了web各层的解决方案,可以和当前主流的框架进行整合。
掌握
spring的核心框架:beans core context expression
eclipse安装STL(spring tool)插件
1. Spring IOC(invocation of control) 控制反转
将对象的创建权交给spring容器来管理。去new过程。
User user = new User();// 程序和User的耦合度较高
class UserService{
UserDao dao = new UserDaoImpl();x
UserDao dao = new UserDaoMybatisImpl();
UserDao dao = DaoFactory.getUserDao();
}
底层原理
总结:
IOC就是使用反射+配置文件+工厂模式,去除new关键字,将对象的创建权交给工厂来完成。
1.1 spring 入门环境搭建
-
-
创建java工程
-
引入spring的核心依赖:spring-beans.jar spring-core.jar spring-context.jar spring-expression.jar spring-jcl.jar(增加的spring的日志依赖)
-
创建配置文件
<?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"> <!-- beans是顶层节点 可以定义多个bean标签,标签和标签之间没有先后顺序 --> <!-- id:唯一标识,不能出现特殊字符比如/ class:控制反转需要的类的全限定类名 name:名称,理论上可以重复,在实际开发过程中不允许重复 可以出现特殊字符(/) 在spring整合struts2时,name属性用于定义该请求的 urlPattern --> <bean id="userDao" class="com.sofwin.dao.impl.UserDaoImpl"></bean> </beans>
-
测试
package com.sofwin.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.sofwin.dao.UserDao; public class Test01 { public static void main(String[] args) { // 工厂 // ClassPathXmlApplicationContext // 是基于classpath下的配置文件生成的工厂(配置文件相对于classpath的位置) // a.xml // FileSystemXmlApplicationContext // 基于文件系统中的配置文件生成的工厂对象 // C:\\A\a.xml // 在spring框架下可以出现多个配置文件 ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao dao = (UserDao)context.getBean("userDao");//通过name/id来获取对象 dao.saveUser(); } }
面试问题
ApplicationContext的区别BeanFactory
-
都是接口
-
ApplicatonContex是BeanFactory的子接口
-
在单例模式下(默认bean标签使用的是单例)applicationContext在容器创建时,会实例化所有bean。BeanFactory只有在第一次getBean的时候才实例化对象。在多例模式下都是在getBean时实例化对象
-
1.2 普通bean IOC
<?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">
<!-- beans是顶层节点
可以定义多个bean标签,标签和标签之间没有先后顺序
-->
<!--
id:唯一标识,不能出现特殊字符比如/
class:控制反转需要的类的全限定类名
name:名称,理论上可以重复,在实际开发过程中不允许重复
可以出现特殊字符(/)
在spring整合struts2时,name属性用于定义该请求的
urlPattern
scope:作用域
默认是singleton 单例
prototype 多例
request 每次请求生成一个对象
session 每次回话生成一个对象
application
websocket
-->
<bean id="userDao" class="com.sofwin.dao.impl.UserDaoImpl" scope="prototype" ></bean>
</beans>
1.3 静态工厂 Bean IOC
工厂中创建实例的方法是静态方法
<!--
静态方法的调用是类名.方法名
factory-method:用于指定静态方法的方法名
虽然class是工厂类型,但是getBean获取的实例应该是factory-method对应的
方法的返回值类型
-->
<bean id="userDao" class="com.sofwin.util.DaoFactory" factory-method="getUserDao"></bean>
package com.sofwin.util;
import com.sofwin.dao.UserDao;
import com.sofwin.dao.impl.UserDaoImpl;
public class DaoFactory {
public static UserDao getUserDao() {
return new UserDaoImpl();
}
public static UserDao getUserDao2() {
return new UserDaoImpl();
}
public static UserDao getUserDao3() {
return new UserDaoImpl();
}
}
1.4 实例工厂Bean IOC
工厂中创建实例的方法是普通方法
<!--
实例工厂的IOC需要分2步执行
1.工厂IOC
-->
<bean id="factory" class="com.sofwin.util.DaoFactory">
</bean>
<!--
2.指定调用某个工厂对象的某个方法
factory-bean:用于指定工厂的id
factory-method
-->
<bean id="userDao" factory-bean="factory" factory-method="getUserDao"></bean>
1.5 Bean的生命周期
-
构造方法执行(实例化时)
-
初始化方法执行(构造方法执行以后) init-method
-
销毁方法 destroy-method
1.6 后处理Bean
是spring提供的用于监听容器中对象初始化的Bean。注意:该bean是直接由spring来调用的,不需要指定id,需要实现指定接口BeanPostProcessor
package com.sofwin.util;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class SofwinBean implements BeanPostProcessor {
/**
* 初始化方法执行前执行
* bean:监控到的bean
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(bean);
System.out.println(beanName);
return bean;
}
/**
* 初始化方法执行后执行
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(bean);
System.out.println(beanName);
return bean;
}
}
<bean class="com.sofwin.util.SofwinBean"></bean>
1.7 基于annotation的IOC
第一类:用于替换xml中的bean标签 id class
第二类:用于定义生命周期的
注意
需要开启组件扫描,需要添加AOP依赖
<?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约束
1.添加namespace xmlns:context="http://www.springframework.org/schema/context"
2.添加约束contxt.xsd
开启组件扫描
base-package:指定需要扫描的包
-->
<context:component-scan base-package="com.sofwin"></context:component-scan>
</beans>
一下注解都是类级别的注解,用于替换xml中的bean
id :注解中的value属性对应的就是xml中的id,可以不写,类名首字母小写就是id
classpath:注解是类级别的注解
-
@Component(原生态注解)
衍生注解(除了@Controller其余的注解和@Component一样
-
@Controller
-
@Service
-
@Repository
注解适用于开发过程中自定义Bean的处理。xml用于开发中第三方架构的Bean的处理
init-method:@PostConstructor
destroy-method:@PreDestroy
1.8 DI(Dependency injection)
依赖注入必须使用IOC的环境,依赖的双方都必须交给spring管理
extend
has a
use a 依赖
contains a
Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式的new一个B的对象。
采用依赖注入技术之后,A的代码只需要定义一个私有的B对象,不需要直接new来获得这个对象,而是通过相关的容器控制程序来将B对象在外部new出来并注入到A类里的引用中。而具体获取的方法、对象被获取时的状态由配置文件(如XML)来指定。 [1]
class A{
B b;
C c;
}
// 不关注A,B,C对象的生成过程(容器来生成的)
// 不关注b的注入过程
1.8.1 基于xml的依赖注入
简单类型的依赖注入
-
setter方法注入
可以属性,并且包含有公有的setter方法的属性依赖注入到对象中
<?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 definitions here -->
<bean id="user" class="com.sofwin.pojo.User">
<!--
setter方法注入
name:属性的属性名
value:简单类型的值
ref:引用地址(bean的id),被引用的实体类的bean的id
-->
<property name="id" value="100"></property>
<property name="name" value="100admin"></property>
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.sofwin.pojo.Dept">
<property name="id" value="110"></property>
<property name="name" value="deptName"></property>
</bean>
</beans>
Class userClass = Class.forName("");
Object obj = userClass.newInstance();
String methodName ="setId";
Method m = userClass.getDeclaredMethod(methodName,)
m.invoke(obj,100);
-
构造方法注入
可以重载构造方法,依赖的对象通过构造方法注入
<?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 definitions here -->
<bean id="user" class="com.sofwin.pojo.User">
<!--
用于指定构造方法的输入值
name:构造方法中形参名称
type:指定形参类型(可以省略)
index:代表参数的索引 (name二选一)
value:实参
ref
-->
<constructor-arg index="0" type="java.lang.String" value="100"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="admin"></constructor-arg>
</bean>
<bean id="dept" class="com.sofwin.pojo.Dept">
<property name="id" value="110"></property>
<property name="name" value="deptName"></property>
</bean>
</beans>
-
P命名空间注入
-
在配置文件中构建p命名空间
<?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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- bean definitions here -->
<!--
由于p命名空间无法检测属性的类型
p:属性名=简单数据类型
p:属性名-ref=引用数据类型注入
-->
<bean id="user" class="com.sofwin.pojo.User" p:id="100" p:name="admin" p:dept-ref="dept">
</bean>
<bean id="dept" class="com.sofwin.pojo.Dept">
<property name="id" value="110"></property>
<property name="name" value="deptName"></property>
</bean>
</beans>
-
SPEL表达式注入
#{变量}
#{表达式}
#{对象.属性}
<!-- bean definitions here -->
<!--
由于p命名空间无法检测属性的类型
p:属性名=简单数据类型
p:属性名-ref=引用数据类型注入
-->
<bean id="user" class="com.sofwin.pojo.User" p:id="#{dept.id}" p:name="admin" p:dept-ref="dept">
</bean>
<bean id="dept" class="com.sofwin.pojo.Dept">
<property name="id" value="#{T(java.lang.Math).random*100}"></property>
<property name="name" value="deptName"></property>
</bean>
引用类型的依赖注入
-
setter方法注入
-
构造方法注入
<?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 definitions here -->
<bean id="user" class="com.sofwin.pojo.User">
<!--
用于指定构造方法的输入值
name:构造方法中形参名称
type:指定形参类型(可以省略)
index:代表参数的索引 (name二选一)
value:实参
ref:用于引用的id
-->
<constructor-arg index="0" ref="dept"></constructor-arg>
</bean>
<bean id="dept" class="com.sofwin.pojo.Dept">
<property name="id" value="110"></property>
<property name="name" value="deptName"></property>
</bean>
</beans>
-
P命名空间注入
-
SPEL表达式注入
其他类型的依赖注入
在整合其他第三方架构时,需要使用
-
list
<!--
用于注入list属性的
-->
<list>
<!--
list中增加简单类型的数据
-->
<value>1</value>
<value>2</value>
<value>3</value>
</list>
<!--
用于注入list属性的
-->
<list>
<!--
ref:
bean用于放引用类型的bean的id
-->
<ref bean="dept"/>
<ref bean="dept"/>
</list>
-
array
<array>
<value>1</value>
<value>2</value>
<value>3</value>
<!--
自定义pojo类型的数组 ref bean
-->
<ref/>
</array>
-
properties
注意
.properties配置文件 key=value key和value都 不能使用“” jdbc.userName=root
<property name="pros">
<props>
<prop key="userName">admin</prop>
<prop key="userName1">admin1</prop>
<prop key="userName2">admin2</prop>
</props>
</property>
-
map
<property name="map">
<map>
<!--
一个键值对
key:简单类型的key
key-ref:引用类型的key对应的bean id
value:简单类型的值
value-ref:引用类型的值对应的bean id
-->
<entry key="name" value="admin"></entry>
<entry key="name1" value-ref="dept"></entry>
<entry key-ref="dept" value="admin2"></entry>
<entry key-ref="dept" value-ref="dept"></entry>
</map>
1.8.2 基于annotation的依赖注入
-
开启组件扫描
注解
1. @value
注入简单类型的属性
属性级别:
方法级别
参数级别
package com.sofwin.pojo;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class User {
// 简单类型的属性的依赖注入可以将@Value注解写在
// 属性中也可以将@Value写在setter方法上
@Value(value="1000")
private Integer id;
@Value(value="admin")
private String name;
private Integer age;
private String pwd;
private List<Integer> ids;
private List<Dept> depts;
private Integer[] array;
private Properties pros;
private Map map;
private Dept dept;// 用户所属部门
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
public void setDepts(List<Dept> depts) {
this.depts = depts;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
public Integer[] getArray() {
return array;
}
public void setArray(Integer[] array) {
this.array = array;
}
public List<Dept> getDepts() {
return depts;
}
public Properties getPros() {
return pros;
}
public void setPros(Properties pros) {
this.pros = pros;
}
}
-
按类型注入
@Autowired(自动装配)
// ref
// 在注入时按照类型注入
// 容器中不能出现多个同种类型的对象
@Autowired
private Dept deptsfd;// 用户所属部门
@Autowired(required = false)
private UserDao dao;
-
按名称注入
@Resource
装配机制:默认按照名称注入(属性名为需要注入的bean的id),如果按名称没有注入成功,按类型注入,并且可以强制使用按什么注入
// name指定注入的bean的id
@Resource
private UserDao userDaoImplsxxx;
组合注解
@Autowird
@Qualifer
@Autowired
@Qualifier("userDaoImpl")
private UserDao userDaoImplsxxx;