1、Spring
1.1、简介
认识框架整合:
ssh:struts2+spring+Hibernate
ssm:SpringMvc+Spring+Mybatis
文档:https://docs.spring.io/spring-framework/docs/4.3.24.RELEASE/spring-framework-reference/html/
官网:https://docs.spring.io/spring-framework/docs/current/reference/html/overview.html#overview
官方下载地址:https://repo.spring.io/release/org/springframework/spring/
GitHub:https://github.com/spring-projects/spring-framework/wiki
依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.7</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.7</version>
</dependency>
1.2、优点
spring是一个开源的容器(框架)
spring是一个轻量级的、非入侵式的框架
控制反转ioc、面向切面编程aop
支持事务的处理,对框架整合的支持
总结:spring是一个轻量级的IOC和AOP的框架。
使用spring的好处
-
Spring的Ioc(控制反转和依赖注入)
控制反转,把对象的创建交给spring进行管理
控制反转:就是由容器控制程序之间的(依赖)关系,而非传统实现中,由程序代码直接操控
依赖注入:组件之间的依赖关系由容器在运行期决定 ,由容器动态的将某种依赖关系注入到组件之中 。
从上面我们不难看出:从头到尾Action仅仅是充当了Service的控制工具,这些具体的业务方法是怎样实现的,他根本就不会管,也不会问,他只要知道这些业务实现类所提供的方法接口就可以了。而在以往单独使用Struts框架的时候,所有的业务方法类的生命周期,甚至是一些业务流程都是由Action来控制的。层与层之间耦合性太紧密了,既降低了 数据访问的效率又使业务逻辑看起来很复杂,代码量也很多。,Spring容器控制所有Action对象和业务逻辑类的生命周期,由于上层不再控制下层的生命周期,层与层之间实现了完全脱耦,使程序运行起来效率更高,维护起来也方便。 -
使用Spring的第二个好处(AOP应用):
AOP面向切面,不修改源代码进行增强
事务的处理:
在以往的JDBCTemplate中事务提交成功,异常处理都是通过Try/Catch 来完成,而在Spring中。Spring容器集成了TransactionTemplate,她封装了所有对事务处理的功能,包括异常时事务回滚,操作成功时数据提交等复杂业务功能。这都是由Spring容器来管理,大大减少了程序员的代码量,也对事务有了很好的管理控制。Hibernate中也有对事务的管理,hibernate中事务管理是通过SessionFactory创建和维护Session来完成。而Spring对SessionFactory配置也进行了整合,不需要在通过hibernate.cfg.xml来对SessionaFactory进行设定。这样的话就可以很好的利用Sping对事务管理强大功能。避免了每次对数据操作都要现获得Session实例来启动事务/提交/回滚事务还有繁琐的Try/Catch操作。这些也就是Spring中的AOP(面向切面编程)机制很好的应用。一方面使开发业务逻辑更清晰、专业分工更加容易进行。另一方面就是应用Spirng AOP隔离降低了程序的耦合性使我们可以在不同的应用中将各个切面结合起来使用大大提高了代码重用度
1.3、组成
Spring-Core:
Core包是框架的最基础部分,并提供依赖注入(Dependency Injection)管理Bean容器功能。这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。
Spring-Context:(Spring核心容器<上下文模块>)
核心模块的BeanFactory使Spring成为一个容器,而上下文模块使它成为一个框架。这个模块扩展了BeanFactory的概念,增加了消息、事件传播以及验证的支持。另外,这个模块提供了许多企业服务,例如电子邮件、JNDI访问、EJB集成、远程以及时序调度(scheduling)服务。也包括了对模版框架例如Velocity和FreeMarker集成的支持。
Spring-Aop:
Spring在它的AOP模块中提供了对面向切面编程的丰富支持。例如方法拦截器(servletListener ,controller…)和切点,可以有效的防止代码上功能的耦合,这个模块是在Spring应用中实现切面编程的基础。Spring的AOP模块也将元数据编程引入了Spring。使用Spring的元数据支持,你可以为你的源代码增加注释,指示Spring在何处以及如何应用切面函数。
Spring-Dao:
使用JDBC经常导致大量的重复代码,取得连接、创建语句、处理结果集,然后关闭连接、旧代码中迁移自定义工具类JDBCUtil 也让开发变得繁琐。Spring的Dao模块对传统的JDBC进行了抽象,还提供了一种比编程性更好的声明性事务管理方法。
Spring-Web:
Web上下文模块建立于应用上下文模块之上,提供了WEB开发的基础集成特性,例如文件上传。另外,这个模块还提供了一些面向服务支持。利用Servlet listeners进行IOC容器初始化和针对Web的applicationcontext。
Spring Web MVC:
(Model-View-Controller)Spring为构建Web应用提供了一个功能全面的MVC框架。它提供了一种清晰的分离模型,在领域模型代码和web form之间。并且,还可以借助Spring框架的其他特性。
Spring-ORM:
关系映射模块,ORM包为流行的“关系/对象”映射APIs提供了集成层,包括JDO,Hibernate和iBatis(MyBatis)。通过ORM包,可以混合使用所有Spring提供的特性进行“对象/关系”映射,方便开发时小组内整合代码。
1.4、拓展
spring boot
—快速开发的脚手架
—基于spring boot可以快速开发单个微服务
—约定大于配置
spring Cloud
spring Cloud是基于spring boot实现的
2、IOC理论推导
1.UserDao接口
2.UserDaoImpl实现类
3.UserService业务接口
4.UserServiceImpl业务实现类
之前的业务受用户的需求要不得的修改源代码,如果代码量大,成本难以想象。
使用set接口实现,已经发生了革命性的变化。
package com.zyf.service;
import com.zyf.dao.UserDao;
import com.zyf.dao.UserDaoHiveImpl;
import com.zyf.dao.UserDaoImpl;
import com.zyf.dao.UserDaoMysqlImpl;
public class UserServcieImpl implements UserService{
private UserDao userDao;
//利用set进行动态实现值的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser(){
userDao.getUser();
}
}
之前,程序是主动创建对象,用户权在程序员手上
现在,使用了set注入后,程序不再有主动性,而是成了被动的接收对象
因此,程序员不用再管理对象的创建了,系统的耦合性极大的降低了,我们可以更加专注与业务的实现。
3、HelloSpring
1、导入Spring相关的jar包
spring需要导入commons-logging进行日志记录,我们利用maven自动下载依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2、编写相关的代码
2.1、编写Hello实体类
package com.zyf.pojo;
public class Hello {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}
2.2、编写spring文件,命名为beans.xml
<?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">
<!--使用spring来创建对象,在spring中这些都被称为bean
类型 变量名 = new 类型()
Hello hello = new Hello();
id = 变量名
class = new 的对象
property 相当于给对象中的属性设置一个值
bean == 对象 new Hello();
-->
<bean id="hello" class="com.zyf.pojo.Hello">
<property name="str" value="Spring"/>
</bean>
</beans>
2.3、测试
import com.zyf.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取spring的上下文对象!
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象都在Spring中管理了,需要使用直接去里面拉取就好
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
}
思考
hello对象是谁创建的
spring
hello对象的属性是怎么设置的
spring容器
这个过程就叫控制反转:
控制:谁来控制对象的创建,传统应用程序的对象是有程序本身控制创建的,使用spring后,对象由Spring来创建。
反转:程序本身不创建对象,而变成被动的接收对象
依赖注入:利用set方法进行注入
IOC:编程思想,主动的编程编程被动的接收
4、IOC创建对象的方式
1、使用无参构造创建对象(默认实现)
2、假设要使用有参构造创建对象。
1.下标赋值
<bean id="user" class="com.zyf.pojo.User">
<!-- <property name="name" value="张乙凡"/>-->
<!-- 第一种下标赋值-->
<constructor-arg index="0" value="张乙凡说Java"/>
</bean>
2.类型
<!-- 第二种,通过类型创建,不建议!-->
<bean id="user" class="com.zyf.pojo.User">
<constructor-arg type="java.lang.String" value="张乙凡"/>
</bean>
3.直接通过参数名来设置
<bean id="user" class="com.zyf.pojo.User">
<constructor-arg name="name" value="张乙凡"/>
</bean>
总结:在配置文件加载的时候,容器中管理的对象就已经初始化了
5、Spring配置
5.1、别名alias
<!-- 别名,如果添加了别名,我们就可以使用别名获取这个对象-->
<alias name="user" alias="user1d123d123"/>
## 5.2、Bean
```xml
<!-- id:bean的唯一标识符,也就是相当于我们学的对象名
class:bean对象所对应的全限定名:包名+类名
name:也是别名-->
<bean id="UserT" class="com.zyf.pojo.UserT" name="user2,u2,u3;u4">
</bean>
5.3、import
一般用于团队开发,可以将多个配置文件,导入合并为一个
假设现在项目中有多个人开发,这3人负责不同的开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的applicationContext.xml
张三
李四
王五
<import resource="beans.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>
6、依赖注入
dependencies Inject
6.1、构造器注入c命名空间
上面有
6.2、Set方式注入(重点)p命名空间
—依赖注入:Set注入!
—依赖:bean对象的创建依赖于容器
—注入bean对象中的所有属性,由容器来注入
环境搭建
1.复杂类型
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
2.真实测试
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
}
//get set toString自己写
3.applicationContext.xml
<?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="student" class="com.zyf.pojo.Student">
<property name="name" value="张乙凡"/>
</bean>
</beans>
4.测试类
public class MyTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.getName());
}
}
5.完善注入信息
<?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="address" class="com.zyf.pojo.Address">
<property name="address" value="阿拉宁波"/>
</bean>
<bean id="student" class="com.zyf.pojo.Student">
<!--第一种,普通值注入,value-->
<property name="name" value="张乙凡"/>
<!--第二种,bean注入,ref-->
<property name="address" ref="address" />
<!--数组注入,ref-->
<property name="books">
<array>
<value>《红楼梦》</value>
<value>《水浒传》</value>
<value>《三国演义》</value>
<value>《西游记》</value>
</array>
</property>
<!--List -->
<property name="hobbys">
<list>
<value>听歌</value>
<value>看电影</value>
<value>敲代码</value>
<value>打游戏</value>
</list>
</property>
<!--Map -->
<property name="card">
<map>
<entry key="身份证号" value="612232018010547"/>
<entry key="银行卡" value="6542049184014"/>
</map>
</property>
<!--Set-->
<property name="games">
<set>
<value>LOL</value>
<value>COC</value>
<value>穿越火线</value>
</set>
</property>
<!--null-->
<property name="wife">
<null/>
</property>
<!--Properties-->
<property name="info">
<props>
<prop key="学号">201801547</prop>
<prop key="姓名">张乙凡</prop>
<prop key="班级">软工181</prop>
<prop key="driver">200031231</prop>
<prop key="url">http://hadoop102:</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
</beans>
6.3、拓展式方式注入
p命名空间和c命名空间进行注入
用法:
<?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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- p命名空间,可以直接注入属性的值:property -->
<bean id="user" class="com.zyf.pojo.User" p:name="张二饭" p:age="23"/>
<!-- c命名空间,可以通过构造器注入,construct-args -->
<bean id="user2" class="com.zyf.pojo.User" c:name="张全蛋" c:age="33"/>
</beans>
测试:
@Test
public void test2(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = (User) context.getBean("user");
//Object user = context.getBean("user2",User.class);//在后面机上类型就不用强转了
System.out.println(user);
}
注意点:
p、c命名空间不能直接使用,要导入约束
xmlns:p=“http://www.springframework.org/schema/p”
xmlns:c=“http://www.springframework.org/schema/c”
6.4、bean的作用域
1.代理模式(Spring默认机制)
<bean id="user2" class="com.zyf.pojo.User" c:name="张全蛋" c:age="33" scope="singleton" />
2.原型模式:每次从容器中get的时候,都会产生一个对象
<bean id="user2" class="com.zyf.pojo.User" c:name="张全蛋" c:age="33" scope="prototype" />
3.其余的request、session、application都只能在web开发中使用
7、Bean的自动装配
—自动装配是Spring满足bean依赖的一种方式
—Spring会在上下文中自动寻找,并自动给bean装配属性
在Spring中有三种装配的方式
1.在xml中显示的配置
2.在java中显示配置
3.隐式的自动装配bean(重要)
7.1、测试
环境搭建:一个人有两个宠物!
7.2、ByName自动装配
<!--
byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id!
-->
<bean id="person" class="com.zyf.pojo.Person" autowire="byName">
<property name="name" value="张大帅比"/>
</bean>
7.3、ByType
<bean id="cat" class="com.zyf.pojo.Cat"/>
<bean id="dogWE" class="com.zyf.pojo.Dog"/>
<!--
byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id!
byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean!
-->
<bean id="person" class="com.zyf.pojo.Person" autowire="byType">
<property name="name" value="张大帅比"/>
<!-- <property name="cat" ref="cat"/>-->
<!-- <property name="dog" ref="dog"/>-->
</bean>
小结:
—byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
—byName的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性类型一致
7.4、使用注解实现自动装配
jdk1.5支持的注解,spring2.5就支持了
要使用注解须知
1、导入约束,context约束
2、配置注解的支持 context:annotation-config/注解的支持
<?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/>
</beans>
@Autowired
@Autowired为Spring提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入。
直接在实体类的属性上使用即可,也可以在set方法上使用!使用了@Autowired我们可以不编写set方法,前提是自动装配的属性在IOC(Spring)容器存在,且符合 ByName!
public class Person {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;
注解用反射实现,可以忽略set方法
注意:
@Nullable 字段标记了这个注解,说明这个字段可以为null;
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { boolean required() default true; }
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解完成的时候,可以使用@Qualifiler(value=“xxx”)去配置@Autowired的使用,指定一个唯一的bean对象注入
public class Person { //如果显示的定义了Autowired属性为false,说明这个对象可以为null,否则不允许为空 @Autowired(required = false) @Qualifier(value="cat213") private Cat cat; @Autowired @Qualifier(value="dog222") private Dog dog; private String name; <bean id="cat213" class="com.zyf.pojo.Cat"/> <bean id="cat" class="com.zyf.pojo.Cat"/> <bean id="dog222" class="com.zyf.pojo.Dog"/>
@Resource
public class Person {
@Resource(name = "cat2")
private Cat cat;
@Resource
private Dog dog;
}
@Resource默认按照ByName自动注入,由J2EE提供,需要导入包javax.annotation.Resource。@Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。
所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略。’
注意:最好是将@Resource放在setter方法上,因为这样更符合面向对象的思想,通过set、get去操作属性,而不是直接去操作属性。
小结:@Autowired和@Resource的区别:
——都是用来自动装配的,都可以放在属性字段上
——@Autowired通过byname的方式实现,而且必须要求这个对象存在!
——@Resource默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!
——执行顺序不同:@Autowired通过byname的方式实现,@Resource默认通过byname的方式实现
@Resource装配顺序:
①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入
8、使用注解开发
在spring4之后,要使用注解开发,就必须保证aop的包导入了(pom)。
使用注解需要导入context约束,增加注解的支持。
1.bean
2.属性如何注入
//@Component 组件 等价于 <bean id="user" class="com.zyf.pojo.User"/>
@Component
public class User {
public String name ;
//相当于<property name="name" value="张乙凡" />
@Value("张乙凡")
public void setName(String name){
this.name=name;
}
}
3.衍生的注解
@Component有几个衍生注解,在web开发中,会按照mvc三层架构分层
dao @Repository
service @Service
controller @Controller
这四个注解的功能都是一样的,代表将某个类注册到Spring中,装配Bean
4.自动装配配置
—@Autowired自动装配的环境比较复杂,如果@Autowired自动装配无法通过一个注解完成的时候,可以使@Qualifiler(value=“xxx”)去配置
—@Nullable 字段标记了这个注解,说明这个字段可以为null;
—@Resource默认通过byname的方式实现,类型。如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!
5.作用域
//@Component 组件 等价于 <bean id="user" class="com.zyf.pojo.User"/>
@Component
@Scope("signleton")
public class User {
public String name ;
//相当于<property name="name" value="张乙凡" />
@Value("张乙凡")
public void setName(String name){
this.name=name;
}
}
6.小结
xml与注解
xml更加万能,适用于任何场合!维护简单方便
注解更方便,但不是自己的类使用不了,维护相对复杂
xml与注解最佳实践
xml用来管理bean;
注解只负责完成属性的注入;
在使用过程中需要注意:必须让注解生效,就需要开启注解的支持
<!-- 指定要扫描的包,这个包下的注解就会生效--> <context:component-scan base-package="com.zyf"/> <context:annotation-config/>
9、使用Java的方式配置Spring
我们现在要完全不使用spring的xml配置,全权交给Java来做。
JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能!
实体类
//这个注解的意思是说这个类被spring接管了,注册到了容器当中
@Component
public class User {
private String name;
public String getName() {
return name;
}
@Value("张乙凡")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
配置类
//这个注解也是说这个类被spring接管了,注册到了容器当中,因为它本来就是一个@Component
//@Configuration代表这是一个配置类,就和我们之前看到的beans.xml
@Configuration
@ComponentScan("com.zyf.pojo")
@Import(ZyfConfig2.class)
public class ZyfConfig {
//注册一个bean,就相当于我们之前写的一个bean标签
//这个方法的名字,就相当于bean标签中的class属性
@Bean
public User user(){
return new User();//就是返回要注入到bean的对象!
}
}
测试类
public class MyTest {
public static void main(String[] args) {
//如果完全使用了配置类方式去做,我们就只能通过AnnotationconfigConext来获取容器,通过配置类的class对象加载
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ZyfConfig.class);
User getUser =(User) context.getBean("user");
System.out.println(getUser.getName());
}
}
SpringBoot里这种纯Java的配置方式非常常见。
10、代理模式
为什么要学习代理模式?因为这是SpringAOP的底层! 【Spring Aop和Spring mvc】
代理模式的分类:
静态代理
动态代理
10.1、静态代理
角色分析:
—抽象角色:一般会使用接口或者抽象类来解决
—真实角色:被代理的角色
—代理角色:代理真实角色,代理真实角色后,我们会做一些附属操作
—客户:访问代理对象的人!
代码步骤
1.接口:
public interface Rent {
public void rent();
}
2.真实角色
//房东
public class Host implements Rent{
public void rent(){
System.out.println("房东要出租房子");
}
}
3.代理角色
package com.zyf.demo01;
//代理角色
public class Proxy {
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
//租房
public void rent(){
seeHouse();
host.rent();
hetong();
fare();
}
//看房
public void seeHouse(){
System.out.println("中介带你看房");
}
//收取中介费
public void fare(){
System.out.println("收取中介费");
}
//签租赁合同
public void hetong(){
System.out.println("签租赁合同");
}
}
4.客户端访问代理角色
public class Client {
public static void main(String[] args) {
//房东要出租房子
Host host = new Host();
//host.rent();
//代理,中介帮房东租房子,代理角色会用附属操作
Proxy proxy = new Proxy(host);
//通过代理出租房子
proxy.rent();
}
}
代理模式的好处:
(1)可以使真实角色的操作更加纯粹,不用去关注一些公共业务
(2)公共也就交给代理角色,实现了业务的分工!
(3)公共业务发生扩展的时候,方便集中管理
缺点:
(1)一个真实角色就会产生一个代理角色,代码量翻倍,效率低。
10.2、加深理解
对应08-demo02
AOP的实现机制就是横向开发,像demo02里加一个Log一样
纵向开发
dao->service->controller->前端
10.3、动态代理
—动态代理和静态代理角色一样
—动态代理的代理类是动态生成的,不是我们直接写好的
—动态代理分为两大类:基于接口的动态代理,基于类的动态代理
基于接口——jdk动态代理
基于类:cglib
Java字节码实现:JAVAsist
了解两个类 proxy代理、InvocationHandler调用处理程序
动态代理的好处:
—可以是真实角色的操作更加纯粹,不用去关注一些公共的业务
—公共也就交给代理角色,实现了业务的分工
—公共业务发生扩展的时候,方便集中管理
—一个动态代理类代理的是一个接口,一般就是对应的一类业务
—一个动态代理类可以代理多个类,只要是实现类同一个接口即可
—
11、AOP
11.1、什么是AOP?
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
11.2、AOP在Spring中的作用
提供声明式事务:允许用户自定义切面
- 横切关注点:跨越应用程序多个模块的方法或功能.既是,与我们业务逻辑无关,但是我们需要关注的部分,就是横切关注点.如日志,安全,缓存,事务等…
- 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。 Log
- 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。 Log中的方法
- 目标(Target):被通知对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 切入点(PointCut):切面通知 执行的 “地点”的定义。
- 连接点(JointPoint):与切入点匹配的执行点。
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
即 Aop 在 不改变原有代码的情况下 , 去增加新的功能 .
11.3、使用Spring实现AOP
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
方式一:使用Spring的api接口【主要是SpringAPI接口实现】
方式二:自定义类实现AOP【主要是切面定义】
方式三:使用注解方式实现AOP
12、整合Mybatis
步骤:
-
导入jar包
-
编写配置文件
junit
mybatis
MySQL数据库
spring相关
AOP织入
mybatis-spring 网址: http://mybatis.org/spring/zh/index.html【new】
pom.xml
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.2</version> </dependency> </dependencies>
-
测试
1、编写数据源配置
2、sqlSessionFactory
3、sqlSessionTemplate
4、需要给接口添加实现类
5、将自己写的实现类,注入到sping中
6、测试使用
13、声明式事务
1、回顾
—把一组业务当成一个业务来做;要么都成功、要么都失败
—事物在项目开发中十分重要,涉及到数据一致性问题,不可大意
—确保完整性和一致性
事物ACID原则
一、原子性(atomicity)
一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作,这就是事务的原子性
二、一致性(consistency)
事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。
如果数据库系统在运行过程中发生故障,有些事务尚未完成就被迫中断,这些未完成的事务对数据库所作的修改有一部分已写入物理数据库,这是数据库就处于一种不正确的状态,也就是不一致的状态
三、隔离性(isolation)
并发访问数据库时,⼀个⽤户的事务不被其他事务所⼲扰,各并发
事务之间数据库是独⽴的;
四、持久性(durability)
一旦事务提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。–即使发生系统崩溃或机器宕机等故障,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束的状态
思考:
为什么需要事物?
如果不配置事务,可能存在数据提交不一致的情况
如果不在spring中配置声明式事物,就需要在代码中配置事务
事务在项目的开发中十分重要,涉及到数据的一致性和完整性问题,必须严谨对待