本文只用于考试复习,不要打印带进考场。。。
目录
代理设计模式 参考 Spring AOP中的 动态代理 和 静态代理
一、概念、填空
Spring IOC、DI、AOP 的概念
IOC:
控制反转(IoC, Inversion of Control) , 是一个概念, 是一种思想。 控制反转就是对对象控制权的转移, 从程序代码本身反转到了外部容器。 把对象的创建、 初始化、销毁等工作交给spring容器来做。 由spring容器控制对象的生命周期。
DI:
依赖注入(Dependency Injection)。 依赖注入DI是指程序运行过程中, 若需要调用另一个对象协助时, 无须在代码中创建被调用者, 而是依赖于外部容器, 由外部容器创建后传递给程序。
AOP:面向切面编程, 就是将交叉业务逻辑封装成切面, 利用AOP的功能将切面织入到主业务逻辑中。 所谓交叉业务逻辑是指, 通用的、 与主业务逻辑无关的代码, 如安全检查、 事务、 日志等。
若不使用AOP, 则会出现代码纠缠, 即交叉业务逻辑与主业务逻辑混合在一起。 这样, 会使主业务逻辑变的混杂不清。
DI依赖注入的两种方式
Spring 基于构造函数的依赖注入
<bean id="textEditor" class="com.tutorialspoint.TextEditor"> <constructor-arg ref="spellChecker"/> </bean> <bean id="spellChecker" class="com.tutorialspoint.SpellChecker"> </bean>
Spring 基于设值函数的依赖注入
<bean id="john-classic" class="com.example.Person"> <property name="name" value="John Doe"/> <property name="spouse" ref="jane"/> </bean> <bean name="jane" class="com.example.Person"> <property name="name" value="John Doe"/> </bean>
或者
<bean id="john-classic" class="com.example.Person" p:name="John Doe" p:spouse-ref="jane"/> </bean> <bean name="jane" class="com.example.Person" p:name="John Doe"/> </bean>
Spring IOC 和 AOP 的优缺点
IOC:
优点:实现组件之间的解耦,提高程序的灵活性和可维护性。
缺点:创建对象的步骤变复杂了;使用反射来创建对象,所以在效率上会有些损耗;缺少IDE重构的支持,如果修改了类名,还需到XML文件中手动修改,这似乎是所有XML方式的缺憾所在。
AOP:
优点:业务逻辑代码清晰
Spring实现的两种设计模式
工厂模式
工厂模式是根据调用数据返回某个类的一个实例,此类可以是多个类的某一个类。通常,这些类满足共同的规则(接口)或父类。调用者只关心工厂生产的实例是否满足某种规范,即实现的某个接口是否可供自己正常调用(调用者仅仅使用)。该模式给对象之间作出了清晰的角色划分,降低程序的耦合。
接口产生的全部实例通常用于实现相同接口,接口里定义了全部实例共同拥有的方法,这些方法在不同的实现类中实现的方式不同。从而使程序调用者无须关心方法的具体实现,降低了系统异构的代价。
定义Person接口类以及American和Chinese实体类:
//-----------------Person接口定义---------------------// public interface Person { public String sayHello(String name); public String sayGoodbye(String name); } //------------American类实现Person接口----------------// public class American implements Person { public String sayHello(String name){ return name+",hello"; } public String sayGoodbye(String name) { return name+",goodbye"; } } //------------Chinese类实现Person接口-----------------// public class Chinese implements Person { public String sayHello(String name){ return name+",您好"; } public String sayGoodbye(String name) { return name+",下次再见"; } }
工厂类
public class PersonFactory { public Person getPerson(String ethnic) { //无视大小写 if(ethnic.equalsIgnoreCase("chinese")) { return new Chinese(); }else{ return new American(); } } }
测试类
public class FactoryTest { public static void main(String[] args){ //创建PersonFactory实例 ,获得工厂实例 PersonFactory pf = new PersonFactory(); //定义接口Person实例,面向接口编程 Person p = null; //使用工厂获得person实例 p = pf.getPerson("chin"); //下面调用Person接口方法 System.out.println(p.sayHello("wawa")); System.out.println(p.sayGoodbye("wawa")); //使用工厂获得Person的另一个实例 p = pf.getPerson("ame"); //再次调用Person接口的方法 System.out.println(p.sayHello("wawa")); System.out.println(p.sayGoodbye("wawa")); } }
由此可看出,主程序从Person 接口的具体类中解耦出来,而且程序调用者无须关心Person 的实例化过程,主程序仅仅与工厂服务定位结合在一起,可获得所有工厂能产生的实例。具体类的变化,接口无须发生任何改变,调用者程序代码部分也无须发生任何改动。
单态模式/单例模式
单态模式限制了类实例的创建,但采用这种模式设计的类,可以保证仅有一个实例,并可提供访问该实例的全局访问点。J2EE应用的大量组件,都需要保证一个类只有一个实例。比如数据库引擎访问点只能有一个。
更多的时候,为了提高性能,程序应尽量减少Java 对象的创建和销毁时的开销。使用单态模式可避免Java 类被多次实例化,让相同类的全部实例共享同一内存区。
为了防止单态模式的类被多次实例化,应将类的构造器设成私有,这样就保证了只能通过静态方法获得类实例。而该静态方法则保证每次返回的实例都是同一个,这就需将该类的实例设置成类属性,由于该属性需要被静态方法访问,因此该属性应设成静态属性。
//单态模式测试类 public class SingletonTest { //该类的一个普通属性 int value; //使用静态属性保存该类的一个实例 private static SingletonTest instance; //构造器私有化,避免该类被多次实例化 private SingletonTest(){ System.out.println("正在执行构造器..."); } //提供静态方法返回该类实例 public static SingletonTest getInstance(){ //实例化类实例前,先检查该实例是否存在 if(instance == null){ //如果不存在,则新建一个实例 instance = new SingletonTest(); } //返回该类的成员变量:该类的实例 return instance; } //以下提供对普通属性value的getter和setter方法 public int getValue(){ return value; } public void setValue(int values){ this.value = values; } public static void main(String args[]){ SingletonTest t1 = SingletonTest.getInstance(); SingletonTest t2 = SingletonTest.getInstance(); t2.setValue(9); System.out.println(t1 == t2); } }
从程序最后的打印结果可以看出,该类的两个实例完全相同。这证明单态模式类的全部实例是同一共享实例。程序里虽然获得了类的两个实例,但实际上只执行一次构造器,因为对于单态模式的类,无论有多少次的创建实例请求,都只执行一次构造器。
在Spring中的实现
使用工厂设计模式创建对象
p = (Person)ctx.getBean("chinese");
创建出来的对象是单态的,使用了单态设计模式
p1 = (Person)ctx.getBean("Chinese");
Person p2 = null;
p2 = (Person)ctx.getBean("Chinese");
System.out.println(p1 == p2); //true
Spring AOP中的 动态代理 和 静态代理
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。动态代理 与 静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
Spring AOP使用动态代理技术在运行期间织入增强的代码,主要有两种代理机制:基于JDK的动态代理、基于CGLib的动态代理。
静态代理
类图实例
虚线箭头:依赖关系是用一套带箭头的虚线表示的;如下图表示A依赖于B;他描述一个对象在运行期间会用到另一个对象的关系;
实线箭头:关联关系是用一条直线表示的;它描述不同类的对象之间的结构关系;它是一种静态关系, 通常与运行状态无关,一般由常识等因素决定的;它一般用来定义对象之间静态的、天然的结构; 所以,关联关系是一种“强关联”的关系;
三角空心实线箭头:泛化关系,类的继承结构表现在UML中为:泛化(generalize)与实现(realize);
代码实例
//抽象角色 public interface Subject { public void request(String param); } //目标角色 public class RealSubject implements Subject{ @Override public void request(String param) { System.out.println("param:"+param); } } //静态代理类 public class StaticProxy implements Subject{ Subject realSubject; public StaticProxy(Subject realSubject) { this.realSubject=realSubject; } public void before(String param){ if(!param.equals("magicalwolf"))//验证参数 throw new IllegalArgumentException(); } @Override public void request(String param) { before(param); realSubject.request(param); } } //测试类 public class Main { public static void main(String[] args) { Subject target=new RealSubject(); Subject proxy=new StaticProxy(target); proxy.request("magicalwolf"); proxy.request("hello"); } } 输出:param:magicalwolf Exception in thread "main" java.lang.IllegalArgumentException ......
基于JDK的动态代理和基于CGLib的动态代理具体实现参考
https://blog.csdn.net/DoUUnderstand/article/details/78865385
Spring两种代理方式
若目标对象实现了接口,spring默认使用JDK的动态代理。
优点:因为有接口,所以使系统更加松耦合
缺点:为每一个目标类创建接口若目标对象没有实现任何接口,spring使用CGLIB进行动态代理。
优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。
缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。若目标对象实现了接口,但是强制cglib代理,则使用cglib代理
bean的作用域
作用域 描述 singleton 该作用域将 bean 的定义的限制在每一个 Spring IoC 容器中的一个单一实例(默认)。 prototype 该作用域将单一 bean 的定义限制在任意数量的对象实例。 request 该作用域将 bean 的定义限制为 HTTP 请求。只在 web-aware Spring ApplicationContext 的上下文中有效。 session 该作用域将 bean 的定义限制为 HTTP 会话。 只在web-aware Spring ApplicationContext的上下文中有效。 global-session 该作用域将 bean 的定义限制为全局 HTTP 会话。只在 web-aware Spring ApplicationContext 的上下文中有效。 实例:
<bean id="..." class="..." scope="singleton"> <!-- collaborators and configuration for this bean go here --> </bean>
AOP基本术语介绍
切面
切面泛指交叉业务逻辑。 比如事务处理、 日志处理就可以理解为切面。 常用的切面有通知与顾问。 实际就是对主业务逻辑的一种增强。
连接点
连接点指切面可以织入的位置。
切入点
切入点指切面具体织入的位置。
织入
织入是指将切面代码插入到目标对象的过程。
通知(Advice)
通知是切面的一种实现, 可以完成简单织入功能(织入功能就是在这里完成的) 。通知定义了增强代码切入到目标代码的时间点, 是目标方法执行之前执行, 还是之后执行等。 通知类型不同, 切入时间不同。顾问(Advisor)
顾问是切面的另一种实现, 能够将通知以更为复杂的方式织入到目标对象中, 是将通知包装为更复杂切面的装配器。 不仅指定了切入时间点,还可以指定具体的切入点。
AspectJ中常用的通知有五种类型
- 前置通知(Before Advice):在切入点选择的连接点处的方法之前执行的通知,该通知不影响正常程序执行流程(除非该通知抛出异常,该异常将中断当前方法链的执行而返回)。
- 后置通知(After Advice):在切入点选择的连接点处的方法之后执行的通知(无论方法执行是否成功都会被调用)。
- 后置返回通知(After returning Advice):在切入点选择的连接点处的方法正常执行完毕时执行的通知,必须是连接点处的方法没抛出任何异常正常返回时才调用。
- 后置异常通知(After throwing Advice): 在切入点选择的连接点处的方法抛出异常返回时执行的通知,必须是连接点处的方法抛出任何异常返回时才调用异常通知。
- 环绕通知(Around Advices):环绕着在切入点选择的连接点处的方法所执行的通知,环绕通知可以在方法调用之前和之后自定义任何行为,并且可以决定是否执行连接点处的方法、替换返回值、抛出异常等等。
执行顺序
分为两种情况:正常执行和执行发生异常情况
图示:
@Around->@Before->Method->@Around->@After->@AfterReturning
@Around->@Before->Method(throw Exception)->@Around->@After->@AfterThrowing
Maven用途及优点
maven是一个项目构建和管理的工具,提供了帮助管理 构建、文档、报告、依赖、scms、发布、分发的方法。
maven的好处在于可以将项目过程规范化、自动化、高效化以及强大的可扩展性。
通俗点说:
1、使用pom.xml统一管理jar包,规范自动高效;
2、使用maven一键构建项目,便捷;
HTTP 相关
看博客里的1、2、4 足够了
MyBatis 优点
优点:
1. 易于上手和掌握。
2. sql写在xml里,便于统一管理和优化。
3. 解除sql与程序代码的耦合。
4. 提供映射标签,支持对象与数据库的orm字段关系映射
5. 提供对象关系映射标签,支持对象关系组建维护
6. 提供xml标签,支持编写动态sql。
SpringBoot 热部署
热启动
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
热部署
开启热部署支持
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <!--fork:设置True,否则可能devtools不会起作用--> <fork>true</fork> </configuration> </plugin>
二、配置、项目、代码
创建SpringBoot项目
两种方法
- 创建Maven项目,修改相关SpringBoot依赖
- Spring Initializr
SpringBoot核心注解
@SpringBootApplication
Spring Boot项目都会有一个Application 类,这个类作为Spring Boot 项目的入口类,在这个入口类中有main 方法,如果我们想要运行该项目,可以在该入口类中run 我们的项目。
MVC架构,分别是什么,用什么实现
M:model模型,用于数据访问层,Service/ServiceImpl类,使用@Service注解;
V:view视图,使用Thymeleaf页面框架构造;
C: control核心,核心,Controller类,使用@Controller/@RestController注解
常用的ORM框架
MyBatis、Hibernate
数据持久层
Thymeleaf 相关
遍历数据
th:each
可遍历的对象:实现Iterable的对象、实现Enumeration的对象、实现Map的对象、任何数组、洽谈对象将被视为包含对象本身的单值列表 (P88)
从后台拿数据
。。。
简单表达式
变量表达式 ${...}
选择表达式 *{...}
消息表达式 #{...}
链接表达式 @{...}
分段表达式 ~{...}
SprngBoot项目中常用注解
@RequestMapping
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
参数说明:
【1】value, method
value:指定请求的实际地址,指定的地址可以是URI Template 模式;
method: 指定请求的method类型, GET、POST、PUT、DELETE等;
【2】consumes,produces
consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
【3】params,headers
params: 指定request中必须包含某些参数值时,才让该方法处理。
headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。
@GetMapping
@GetMapping = @ReqestMapping(method = RequestMethod.GET)
@PostMapping
@PostMapping = @ReqestMapping(method = RequestMethod.POST)
@PathVariable
@PathVariable 是映射 URL 绑定的占位符
通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过@PathVariable("xxx") 绑定到操作方法的入参中。
在一下例子中,请求{API}/xxx/123718237182
则'123718237182'将被作为id传入函数
@GetMapping("/{id}") public Result get(@PathVariable("id") String id) { .... }
@ResponseBody @RequestBody 区别
@ResponseBody 是作用在方法上的,@ResponseBody 表示该方法的返回结果直接写入 HTTP response body 中(一般在使用 @RequestMapping后,返回值通常解析为跳转路径,但是加上 @ResponseBody 后返回结果不会被解析为跳转路径,而是直接写入 HTTP response body 中。) 比如异步获取 json 数据,加上 @ResponseBody 后,会直接返回 json 数据。
@RequestBody 是作用在参数上, 将 HTTP 请求正文插入方法中,使用适合的 HttpMessageConverter 将请求体写入某个对象。
@Resource @Autowired 区别
ps:这两者都是用来自动装配bean 的。
区别:
1、@Autowired 默认按byType自动注入(如果要允许null值,可以设置它的required属性为false),@Resource默认按 byName自动注入;
2、@Autowired 该注解属于Spring,@Resource 该注解属于J2EE
事务相关
概念
是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。
遵循四个原则(ACID):原子性、一致性、隔离性、持久性
管理事务 Spring事务管理API介绍
用于完成事务的提交、 回滚, 及获取事务的状态信息。
PlatformTransactionManager 接口常用的两个实现类
DataSourceTransactionManager: 使用JDBC或MyBatis 进行持久化数据时使用。
HibernateTransactionManager: 使用Hibernate进行持久化数据时使用。注解开启事务
@Transactional
具体参考 https://www.ibm.com/developerworks/cn/java/j-master-spring-transactional-use/index.html
三、编程题
JPA注解 Author/Work
可参考,不全面,可能还会改
@Entity
public class Worker {
@Id
private long id;
@Column
private String title;
@ManyToMany(targetEntity=Author.class)
private List authors;
setter and getter...
}
@Entity
public class Author {
@Id
private long id;
@Column
private String alias;
@ManyToMany(targetEntity=Worker.class)
private List workers;
@OneToOne
private Person person;
setter and getter...
}
@Entity
public class Person {
@Id
private long id;
@Column
private String name;
setter and getter...
}
SpringBoot+MyBatis+Thymeleaf
代理设计模式 参考 Spring AOP中的 动态代理 和 静态代理