Spring复习
- spring是一个轻量级的,非侵入式的,IOC、AOP一站式的,简化企业级开发而生的。
- 核心包非常小
- 业务代码中,不侵入框架代码。
- IOC:控制反转,将生成对象的权利 反转给了spring框架 依赖注入DI 为属性注入值。
- AOP:面向切面编程,将一些与业务代码无关的公共部分抽取出来,使用时通过代理对象调用,从而达到不修改源代码的基础上,增加功能,代码的耦合度降低。
- 一站式框架:数据持久层,web控制层…
如何搭建?
创建spring配置文件 spring.xml文件
在spring.xml文件中配置,需要让spring管理的类<baen id class scope …>
spring框架读取xml文件,解析xml
通过工厂模式+反射机制 创建对象。
在需要使用对象时从spring容器中,注入对象。
spring中常用的注解标签:
- @Controller
@Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。- @RequestMapping
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。- @Autowired
默认按照bean的类型注入数据- @PathVariable
用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数- @requestParam
@requestParam主要用于在SpringMVC后台控制层获取参数,类似一种是request.getParameter(“name”),它有三个常用参数:defaultValue = “0”, required = false, value = “isApp”;defaultValue 表示设置默认值,required 铜过boolean设置是否是必须要传入的参数,value 值表示接受的传入的参数类型。- @Repository
用于注解dao层
spring+jdbc
jdbcTemplate 管理数据源(阿里巴巴 Druid)事务管理
事务管理的最基本的原理是使用AOP。
声明式事务和编程式事务
事务传播行为 是spring框架自身对事务进行功能上的增强。
A 方法 调用 B方法 那么B方法的事务应该如何执行?(把B事务加入到A事务中执行,还是B方法自己创建一个新的独立于A事务。)
spring+mybatis
springMVC
执行流程
BeanFactory和ApplicationContext区别
new User() 创建了一个User对象。
把由spring框架创建的对象称为一个bean。
BeanFactor接口是spring框架中做基础的接口,定义了如何获取bean的方法。
ApplicationContext接口间接继承了BeanFactory接口,在此基础上扩展其功能。
BeanFactory
- 是最基础的,面向spring框架本身的
- 在使用对象时才去创建。
ApplicationContext
- 是面向应用的,增加了功能(支持AOP 事务、)。
- 适合于web应用程序,在服务器启动时就创建。
springBean生命周期
一个对象什么时候创建 什么时候销毁。
spring中bean可能经过5个阶段:
1.实例化创建一个原始的对象,例如new对象 通过反射机制实现 的(框架可以读到类名)。
2.属性赋值(为对象属性进行赋值)
UserService 注入UserDao userDao
3.初始化
我们的bean如果实现了某些接口,就可以去执行这些方法用来初始化我们的对象,重点在于对类进行功能提升。如果此类有增强(aop)就是在此处为bean添加功能。
4.使用
5.销毁
spring中bean是线程安全的吗?
servlect是线程安全的吗?servlect不是线程安全的。
servlet是单例的,在服务器启动时由服务器创建,只创建了一个,因此线程不安全。
- 单例bean不是线程安全的。
单例bean 把一次请求看作是一个线程,很多个请求就是很多个线程,多个线程共享一个bean,不安全。
bean分为有状态bean 和无状态bean。 有状态bean 这个变量可以存储数据 无状态bean 这个变量不能存储数据 假设USerController、User、UserService都是单例的 class USerController{ User user;// 存储用户信息,有状态,不安全 UserService userService;// 不存储数据,无状态的 安全的 }
- 原型bean是线程安全的。
原型bean 是每次使用时,会创建一个对象,不共享,是线程安全的。
Bean循环依赖
- 什么是循环依赖
class A{
自动注入
B b;此时B对象有可能还没有创建
}
class B{
A a;
}
此情况只在spring中出现。
因为spring创建对象时,可以为属性自动注入值,注入时就需要找的所依赖的对象。
产生循环依赖的问题:
A创建时需要B—> B去创建---->需要A 从而产生循环
解决办法:spring三级缓存机制
每一个缓存可以理解为一个map容器(把不同的对象做一个临时存储)。
- 一级缓存
存放创建、初始化完成的完整的bean。- 二级缓存
存储原始的对象。- 三级缓存
加入B类如果有需要增强的功能,那么把这个半成品的B对象继续放在三级缓存中去增强功能。
Servlet的过滤器与Spring拦截器区别
区别主要在底层实现方式上有所不同:
- 过滤器实现是依赖于tomcat,请求会先到达过滤器,然后进入servlet
- spring拦截器是框架内部封装的,请求先到达servlet,根据映射地址去匹配拦截器,最终到达控制层
- 过滤器
- 拦截器
建模语言
Unified Modeling Language UML 类图
以可视化图形方式来表示类与类之间的关系,方便理解。
类图的基本元素
-
类
是指具有相同属性、方法和关系的对象的抽象,它封装了数据和行为。 是面向对象程序设计(OOP)的基础,具有封装性、继承性和多态性等三大特性。 在 UML中,类使用包含类名、属性和操作且带有分隔线的矩形来表示。 (1)类名(Name)是一个字符串,例如,Student (2)属性(Attribute)是指类的特性,即类的成员变量. UML按以下格式表示 [可见性]属性名:类型[=默认值] 例如:-name:String 注意: “可见性”表示该属性对类外的元素是否可见 包括公有(Public)、私有(Private)、受保护(Protected)和朋友(Friendly)4 种 在类图中分别用符号+、-、#、~表示。 (3)操作(Operations)是类的任意一个实例对象都可以使用的行为, 是类的成员方法。 UML按以下格式表示 [可见性]名称(参数列表)[:返回类型] 例如:+display():void
-
接口
接口(Interface)是一种特殊的类,它具有类的结构但不可被实例化,只可以被子类实现。 它包含抽象操作,但不包含属性。它描述了类或组件对外可见的动作。 在 UML 中,接口使用一个带有名称的小圆圈来进行表示。
图形类接口的 UML 表示:
- 类图
类图(ClassDiagram)是用来显示系统中的类、接口、协作以及它们之间的静态结构和关系的一种静态模型。它主要用于描述软件系统的结构化设计,帮助人们简化对软件系统的理解,它是系统分析与设计阶段的重要产物,也是系统编码与测试的重要模型依据。
类图中的类可以通过某种编程 语言直接实现。类图在软件系统开发的整个生命
周期都是有效的,它是面向对象系统的建模中最常见的图。下图所示是“计算长
方形和圆形的周长与面积”的类图,图形接口有计算面积和周长的抽象方法,长方形和圆形实现这两个方法供访问类调用。
- 类之间的关系
- 依赖关系:
在A的某个方法中把B类作为参数使用。具有临时性
关联关系:
在一个类中,把另一个类当作属性。2.1 聚合关系:表示一种强关联关系。 学校和老师,学校不存在,老师依然存在。
2.2组合关系:更强烈的关联关系。头和嘴,头不存在了,嘴也就没有存在的意义了。
- 泛化关系:
类继承类,接口继承接口
- 实现关系:
类实现接口
面向对象设计原则
继承和多态 提高代码的可复用性,可拓展性.
单一职责
一个类负责做一件事
优点:低耦合,高内聚。
开闭原则
对扩展开放、对修改关闭
抽象功能、具体实现可以扩展子类
优点:适应性和灵活性、稳定性和延续性、可复用性和可维护性。
里氏替换原则
在任何出现父类的地方都可以用它的子类来替换,且不影响功能(多态)。
Animal animal=new Dog();
依赖倒置
高展模块不应该依赖底层模块,两者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
接口隔离
使用多个专门的接口,而不使用单一的总接口,不强迫新功能实现不需要的方法。
迪米特原则
一个对象应当对其他对象尽可能少的了解,降低耦合。
组合/聚合复用原则
优先使用组合,使系统更灵话,其次才考虑继承,达到复用的目的。
一般而言,如果两个类之间是"Has-A"关系应使用组合或聚合,如果是"Is-A"关系可使用继承。
设计模式(java design patterns)
在前辈们长期开发的过程中,为解决某一类问题总结出的一种较为优化的代码设计结构。提高程序的代码复用性、扩展性、稳定性。
设计模式
创建型模式、结构型模式和行为型模式 3中。
创建型模式:主要负责创建对象 单例,工厂
单例模式
在整个程序中只允许有一个对象。
创建对象 使用构造方法 将构造方法私有化,
只能在本类中创建,这样我们就可以控制数量;
向外界提供一个公共的访问方法。
饿汉式单例 一般又称为急切式单例
在类加载时,就会创建此单例对象,这种写法不会出现线程安全问题。
/**
*
* * 饿汉式单例
* * 一般又称为急切式单例
* * 在类加载时就会创建此单例对象
* *
* * 这种写法不会出现线程安全问题
* *
*/
public class Singleton {
//创建一个对象
private static Singleton instance=new Singleton();
//让构造函数为 private
private Singleton() {
}
//获取唯一可用的对象
public static Singleton getInstance(){
return instance;
}
}
public class Test {
public static void main(String[] args) {
//获取唯一可用的对象
Singleton object1 = Singleton.getInstance();
Singleton object2 = Singleton.getInstance();
Singleton object3 = Singleton.getInstance();
System.out.println(object1);
System.out.println(object2);
System.out.println(object3);
}
}
懒汉式单例
在类加载时,不会创建单例对象,在第一次访问时,才会去创建。
/*
* 懒汉式单例
* 在类加载时,不会创建单例对象,在第一次访问时,才会创建单例对象
*
* 懒汉式单例有线程安全问题,必须要加锁处理
*/
public class Singleton {
//创建一个对象
private static Singleton instance;
//让构造函数为 private,这样该类就不会被实例化
private Singleton() {
}
//获取唯一可用的对象
//这里需要加锁,防止两个线程同时进入if判断中
public static synchronized Singleton getInstance(){
if (instance==null){
instance= new Singleton();
}
return instance;
}
}
public class Test {
public static void main(String[] args) {
//获取唯一可用的对象
Singleton object1 = Singleton.getInstance();
Singleton object2 = Singleton.getInstance();
Singleton object3 = Singleton.getInstance();
System.out.println(object1);
System.out.println(object2);
System.out.println(object3);
}
}
工厂模式
批量创建对象,将创建对象与使用对象分离。
三个角色
- 工厂 负责生产对象的。
- 抽象产品 接口/抽象类 定义
- 具体产品 实现了抽象的接口/抽象类的具体实现类。
以抽象表示具体。
//抽象产品
public interface Product {
void show();
}
//具体产品1
public class ProductA implements Product {
@Override
public void show() {
System.out.println("具体产品1显示...");
}
}
//具体产品2
public class ProductB implements Product {
@Override
public void show() {
System.out.println("具体产品2显示...");
}
}
/*
* 工厂,负责生产对象
*/
public class SimpleFactory {
public Product createProduct(String className){
if(className == null){
return null;
}else{
try {
return (Product) Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
}
}
public class Test {
public static void main(String[] args) {
SimpleFactory simpleFactory = new SimpleFactory();
Product productA = simpleFactory.createProduct("com.ff.javadesign.simplefactory.ProductA");
Product productB = simpleFactory.createProduct("com.ff.javadesign.simplefactory.ProductB");
}
}
代理模式
代理—>代理商 4S店、中介、商城
用户 —> 汽车厂
用户—> 4S店(代理) 买保险,上牌照 —> 汽车厂
当用户不想或不能直接去访问目标对象 可以通过一个中间代理商在用户和目标之间起到一个中间作用。
代理模式优点:
- 保护目标对象
- 对目标对象进行扩展
- 将用户和目标进行分类,降低了耦合度。
AOP是什么?
AOP使用方法 xml
AOP实现原理
代理模式
思想?
静态代理
静态代理一般适用于关系是固定的,代理某类事务必须实现接口。
如果需要代理多个目标对象,那么就需要实现更多的接口,后期维护起来就比较麻烦。
动态代理
实现方式有两种
JDK代理
实现原理是使用Java反射机制,可以动态获取目标类中代理的方法。
不需要代理类指定的去实现某些抽象接口,代理的扩展性好。
动态生成代理对象,要求目标类必须有实现接口。Cglib代理
动态字节码技术
可以在运行中为目标类动态生成一个子类进行方法拦截,从而添加增强功能。
不能代理final所修饰的类,目标类可以不实现任何接口spring中两种都支持
注解
Java注解又称为Java标注,为类,方法,属性,包进行标注,与java文档注释中的标记不同。
可以被编辑到字节码文件中,运行时可以通过反射机制获取到注解标签。
内置的注解
java中已经定义好的注解标记。
- @Override :检查该方法是否是重写方法,如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
- @Deprecated :标记过时方法,如果是使用该方法,会报编译错误。
- @SuppressWarnings : 指示编译器去忽略注解中声明的警告。
- @Retention - 标识这个注解怎么保存,是只在代码中,还是编入 class 文件中,或者是在运行时可以通过反射访问。
元注解
@Target:用于描述注解的使用范围(即:被描述的注解可以用在什么地方.
ElementType.TYPE 可以应用于类的任何元素。
ElementType.CONSTRUCTOR 可以应用于构造函数。
ElementType.FIELD 可以应用于字段或属性。
ElementType.LOCAL_VARIABLE 可以应用于局部变量。
ElementType.METHOD 可以应用于方法级注释。
ElementType.PACKAGE 可以应用于包声明。
ElementType.PARAMETER 可以应用于方法的参数。 @Retention:@Retention 定义了该注解被保留的时间长短:某些注解仅出现在源代码中,而被编译器丢弃;而另一些却被编译在 class 文件中;编译在 class 文件中的注解可能会被虚拟机忽略,而另一些在 class 被装载时将被读取(请注意并不影响 class 的执行,因为注解与 class 在使用上是被分离的)。使用这个 meta-Annotation 可以对注解的“生命周期”
限制。作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效) 取值(RetentionPoicy)有:
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在 class 文件中有效(即 class 保留)
3.RUNTIME:在运行时有效(即运行时保留)
对象克隆
从前端像后端发送的数据,从后端向前端返回的数据,我们通通都是使用一个Model类来完成封装,实际中模型类可以分为好几种。
例如专门用来接收前端数据的,可以加入验证,向dao层传输数据的,这里就需要用到对象的克隆。
为什么要对象克隆?
为什么要克隆,直接new 一个对象不行吗?
克隆的对象可能会包含一些已经修改过的属性,而new的对象的属性值还是初始化时候的值,我们需要去赋值,例如 Student1为前端接收的数据 Student student2=new Student(); student2.setId(student1.getId()); ...... 这样的操作实在是过于麻烦
误区:
Student stu1=new Student(); Student stu2=stu1; 这种方式复制的是引用,也就是对象在内存中的地址。 两个引用指向了同一个对象。
克隆又分为浅克隆与深克隆
- 浅克隆
如果一个对象中关联了其他的引用变量,浅克隆时,只会将关联的对象的引用地址复制出来,并没有创建一个新的对象。
- 深克隆
如果一个对象中关联了其他的引用变量,深克隆时,会将此对象中所关联的对象,也会进行克隆操作,也就是会创建一个新的关联对象。
实现方式:
- 在Java语言中国,通过覆盖Object类的clone()方法可以实现浅克隆。
- 在spring框架中提供了BeanUtils。copyProperties(source,target);
如何实现深克隆?
- 多层次克隆
在关联的类中继续克隆。 - 使用序列化方式和反序列化的方式。