Spring框架:不属于mvc架构的任何一层,不是单纯的代替某一种开发技术
作用
:提供容器,进行对象管理
开源的
轻量级的
非侵入式的
控制反转 IOC
和 面向切面 AOP
的容器框架
- 开源的:免费的
- 轻量级的:占用空间小
- 非侵入式的:在使用框架过程中,几乎不需要使用它的API来编码
程序易于维护,易于扩展
API:定义好的接口,可直接访问,不需要源码
- 控制反转
IOC
:Spring最核心的部分
把程序中对象管理的控制,反转给Spring容器(
Spring核心配置文件
)去做处理
举个栗子:高内聚 低耦合
A :B b = new B;b.方法()耦合度
B :C c = new C;c.方法()耦合度
C
- 面向切面
AOP
:面向切面的编程
把程序中要实现的功能进行分类
- 横切关注点: (与业务不相关的,比较公共的功能点 日志管理 安全性检查。。。)
- 垂直关注点:(系统实现业务功能点 登录 注册 下订单。。。)
IOC:设计思想(对象管理)
尽可能降低程序的耦合度,提高程序的可维护型,可扩展性
- Spring对IOC思想有比较好的实现
- 选用Spring框架的IOC来解决程序中对对象管理的问题
AOP:设计思想(解决程序中横切关注点功能实现)
把代码提到某一个类中去实现,在程序运行或者编译期间,把横切关注点的代码加入到业务代码中,提升开发效率,提高代码重用性
Spring框架的体系结构、
- Spring Core:Spring IOC
- Spring AOP:面向切面编程
- Spring ORM:提供持久层框架进行集合的功能
- Spring DAO:提供与数据库交互的JDBC的过程
- Spring Web:与Servlet技术进行集成的功能
- Spring WebMvc:Spring框架的子框架(代替Servlet技术为完成的控制功能的框架)
- Spring Context:提供企业级开发技术进行集成的功能(发邮件 付款。。。)
搭建Spring工程
- 创建普通的java工程
- 导入Jar包
- 引用Spring配置文件
Spring IOC:单独进行一个对象的管理
Spring在管理对象时,把每一个要管理的独享叫做 bean
bean标签
- id属性:对象在容器中唯一标识
- name属性:唯一标识,与id属性同理
- class属性:要管理的类的全类名
- scape属性:设定bean的作用域
- singleton:默认值 单例模式
- prototype:非单例模式
- request:创建出的bean的生命周期是一个request范围内
- session:创建出的bean的生命周期是一个session范围内
- lazy-init属性:用于设定bean是否延迟初始化
- false:默认值 非延迟初始化 Spring容器加载过程中就完成对象的构建 推荐使用
- true:延迟初始化
<bean id="first" class="spring.bean.FirstBean" />
依赖注入( DI
):基于xml文件进行依赖注入
- 构造注入
xml文件
<!-- 构造注入 -->
<bean id="example" class="Spring.bean.ExampleBean">
//结构属性标签
//constructor-arg:结构--参数
<constructor-arg>
<ref bean="first"/>
</constructor-arg>
<constructor-arg>
<ref bean="second"/>
</constructor-arg>
</bean>
bean.java
public class ExampleBean {
//构造注入
private FirstBean f;
private SecondBean s;
public ExampleBean(FirstBean f,SecondBean s) {
this.f = f;
this.s = s;
}
public void print() {
System.out.println("ExampleBean的print方法");
f.test();
s.run();
}
}
Test
//构造注入
ExampleBean e = (ExampleBean) app.getBean("example");
e.print();//ExampleBean的print方法 // FirstBean //SecondBean
- 属性注入(setter注入)
xml文件
<!-- 属性注入 -->
<bean id="newexample" class="Spring.bean.NewExampleBean">
<!--
property标签:
name:与类中类中成员变量的名字相同
ref:要注入的bean的id
-->
<property name="firstBean" ref="first"/>
<property name="secondBean" ref="second"></property>
</bean>
<bean id="userDAO" class="Spring.dao.UserDAO"></bean>
<bean id="userService" class="Spring.service.UserService">
<property name="dao" ref="userDAO"></property>
</bean>
bean.java
public class NewExampleBean {
private FirstBean firstBean;
private SecondBean secondBean;
public void setSecondBean(SecondBean secondBean) {
this.secondBean = secondBean;
}
//set方法
public void setFirstBean(FirstBean firstBean) {
this.firstBean = firstBean;
}
public void test() {
System.out.println("NewExampleBean的test方法");
firstBean.test();
secondBean.run();
}
}
Test
//属性注入
NewExampleBean ne = (NewExampleBean) app.getBean("newexample");
ne.test();//NewExampleBean的test方法 //FirstBean //SecondBean
UserService service = (UserService) app.getBean("userService");
service.register();//UserService的register方法 //UserDAO的register方法
- 接口注入
- 不同数据类型的依赖注入
- 基本数据类型 字符串(value)
xml文件
- name:数据类中的成员变量的参数名
- value:赋值
<!--不同数据类型的依赖注入 -->
<bean id="student" class="Spring.bean.Student">
<property name="sid" value="111"/>
<property name="sname" value="xiaoli"/>
<property name="sex" value="女"/>
<property name="email" value="111@qq.com"/>
<property name="list">
<list>
<value>111</value>
<value>222</value>
<value>333</value>
</list>
</property>
</bean>
bean.java
- 只提供参数的
set
方法
public class Student {
private int sid;
private String sname;
private String sex;
private String email;
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
public void setSid(int sid) {
this.sid = sid;
}
public void setSname(String sname) {
this.sname = sname;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setEmail(String email) {
this.email = email;
}
public void printInfo() {
System.out.println(sid+" "+sname+" "+sex+" "+email);
for(String s:list) {
System.out.println(s);
}
}
}
Test
//不同数据类型的依赖注入(属性注入)
Student stu = (Student) app.getBean("student");
stu.printInfo();//111 xiaoli 女 111@qq.com
- 空值的依赖注入
<bean id="student" class="Spring.bean.Student">
<property name="sid" value="111"/>
<property name="sname" value="xiaoli"/>
<property name="sex" value="女"/>
//空值
<property name="email" value=""/>
<!--
<property name="email"/>
<null/>
-->
<property name="list">
<list>
<value>111</value>
<value>222</value>
<value>333</value>
</list>
</property>
</bean>
- 引用数据类型的依赖注入(ref)
xml文件
<!-- 构造注入 -->
<bean id="example" class="Spring.bean.ExampleBean">
<constructor-arg>
<ref bean="first"/>
</constructor-arg>
<constructor-arg>
<ref bean="second"/>
</constructor-arg>
</bean>
<!-- 属性注入 -->
<bean id="newexample" class="Spring.bean.NewExampleBean">
<!--
property标签:
name:与类中类中成员变量的名字相同
ref:要注入的bean的id
-->
<property name="firstBean" ref="first"/>
<property name="secondBean" ref="second"></property>
</bean>
<bean id="userDAO" class="Spring.dao.UserDAO"></bean>
<bean id="userService" class="Spring.service.UserService">
<property name="dao" ref="userDAO"></property>
</bean>
- 集合类型的依赖注入
基于注解的配置
注解形式开发
xml文件
<!-- 组件扫描管理某个包中所有类的对象 -->
<context:component-scan base-package="com.service"></context:component-scan>
<context:component-scan base-package="com.dao"></context:component-scan>
在service层的注解中起别名是在Test中 app.getBean()
方法中调用
Test
UserService service = (UserService) app.getBean("userService");
service.login();//UserService的login的方法 UserDAO的login的方法
Spring AOP:解决事务处理
举个栗子:记录程序运行的时间
实现思路:把横切关注点的功能代码单独用一个类去实现,在程序编译或者运行期间,动态的加如该部分代码
- 通知:用于编写横切关注点的代码的类
- 前置通知: 通知的代码在业务代码执行之
前
就执行完毕 - 返回后通知: 通知的代码在业务代码执行之
后
就执行完毕 - 环绕通知:通知的代码在业务代码执行之
前
就执行,在业务代码执行之后
也会执行
bean.java
//环绕通知
public class SelectAdvice implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation method) throws Throwable {
System.out.println("程序运行开始");
Date begin = new Date();
//继续执行业务代码
Object obj = method.proceed();
System.out.println("程序运行结束");
Date end = new Date();
System.out.println("程序运行时间为:"+(end.getTime()-begin.getTime())+"毫秒");
return obj;
}
}
- 抛出通知:业务代码抛出异常时执行通知类代码
- 切入点:定义横切关注点的代码
何时
被执行 - 顾问:切入点与通知的配置器
- 代理:实现
xml文件:4步走
<bean id="select1" class="spring.aop.bean.UserSelectImp1" />
<bean id="select2" class="spring.aop.bean.UserSelectImp2" />
<!-- 管理通知类对象 -->
<bean id="selectAdvice" class="spring.aop.bean.SelectAdvice" />
<!-- 配置切入点 -->
<bean id="selectPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut" >
<property name="pattern" value=".*select" />
</bean>
<!-- 配置顾问 -->
<bean id="selectAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor" >
<property name="advice" ref="selectAdvice" />
<property name="pointcut" ref="selectPointcut" />
</bean>
<!-- 代理 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
Test
public static void main(String[] args) {
//加载Spring容器 入参是Spring核心配置文件相当于src的路径
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserSelect s1 = (UserSelect) app.getBean("select1");
s1.select();
UserSelect s2 = (UserSelect) app.getBean("select2");
s2.select();
}