代理模式
-
代理模式常用的地方:
AOP的功能完全继承到了Spring事务管理、日志和其他各种特性的上下文中。 Authentication权限认证 Logging日志 Transctions Manager事务 Lazy Loading懒加载 Context Process上下文处理 Error Handler错误跟踪(异常捕获机制) Cache缓存处理
-
分为静态代理、动态代理
JDK 动态代理: CGLib 动态代理: cglib.jar (全称 Code Generation Library 代码生成库) asm.jar(全称 assembly,装配)
-
代理的特点:
1、执行者、被代理人 2、对于被代理人来说,这件事情是一定要做的,但是我自己又不想做或者没有时间做,找代理。 3、需要获取到被代理的人个人资料。
-
穷举法:
租房中介:中介和你 火车票黄牛:黄牛和你 媒人:媒婆和你 明星经纪人:经纪人和明星 刘德华要开演唱会(长沙)、准备工作和善后工作 快递:
-
总结:做了一件什么事情呢?
字节码重组
可以做一件什么事情?
可以在每一个方法调用之前加一些代码,在方法调用之后再加一些代码
AOP:事务代理(声明式事务,哪个方法需要加事务,哪个方法不需要加事务)
-
日志监听
service 方法 开启一个事务(open) 事务的执行(是由我们自己的代码完成的) 监听到是否有异常,可能需要根据异常的类型来决定这个事务是否要回滚还是继续提交 (commit/rollback) 事务要关闭(close)
-
代理的原理
1、拿到被代理对象的引用,然后获取它的接口; 2、JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口。 3、把被代理对象的引用也拿到了 4、重新动态生成一个class字节码 5、然后编译
-
JDK代理与cglib代理
JDK代理:实现自InvocationHandler接口,实现代理 cglib代理:实现自MyMethodInterceptor接口,实现代理 JDK的动态动力是通过接口来进行强制转换的 生成以后的代理对象,可以强制转换为接口 CGLib的动态代理是通过生成一个被代理对象的子类,然后重写父类的方法, 生成以后的对象,可以强制转换为被代理对象(也就是用自己写的类), 子类引用赋值给父类。 cglib new出来以后的对象,是被代理对象的子类(继承课我们自己写的那个类), OOP,在new子类之前,实际上默认先调用了我们super()方法的, new了子类的同时,必须先new出来父类,这就相当于是间接的持有了我们父类的引用。 子类重写了父类的所有的方法, 我们改变子类对象的某些属性,是可以间接的操作父类的属性的。
-
Cglib和jdk动态代理的区别?
1、Jdk动态代理:利用拦截器(必须实现InvocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。 2、Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理。
-
什么时候用cglib什么时候用jdk动态代理?
1、目标对象生成了接口 默认用JDK动态代理 2、如果目标对象使用了接口,可以强制使用cglib 3、如果目标对象没有实现接口,必须采用cglib库,Spring会自动在JDK动态代理和cglib之间转换
-
JDK动态代理和cglib字节码生成的区别?
1、JDK动态代理只能对实现了接口的类生成代理,而不能针对类 2、Cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法的增强,但是因为采用的是继承,所以该类或方法最好不要生成final,对于final类或方法,是无法继承的
-
Spring如何选择是用JDK还是cglib?
1、当bean实现接口时,会用JDK代理模式 2、当bean没有实现接口,用cglib实现 3、可以强制使用cglib(在spring配置中加入<aop:aspectj-autoproxy proxyt-target-class=”true”/>)
-
cglib举例:
1、引入依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
2、创建一个被代理人的对象:
public class ZhangSanFindLove {
public void findLove(){
System.out.println("牛郎织女七夕来相会...");
}
}
3、创建一个代理人对象:
public class MyMethodInterceptor implements MethodInterceptor {
/**
* @param clazz 文件的字节码文件
* @return 具体的对象
*/
public Object getInstance(Class clazz){
//通过Enhancer对象进行代理操作
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(clazz);
//设置回调
enhancer.setCallback(this);
//调用Enhancer对象的创建并返回
return enhancer.create();
}
/**
* @param className 文件的全路径名称
* @return 具体的对象
*/
public Object getInstance(String className){
//通过Enhancer对象进行代理操作
Enhancer enhancer = new Enhancer();
//设置父类
try {
enhancer.setSuperclass(Class.forName(className));
} catch (ClassNotFoundException e) {
}
//设置回调
enhancer.setCallback(this);
//调用Enhancer对象的创建并返回
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
System.out.println("我是媒婆,你得给我找个异性");
System.out.println("--------------------------");
/**
* 不能使用invoke,invoke是指向自己
* Cglib是给指定的类添加一个子类对象,所以应该指向父类节点
* 为父类自动塑造出一个子类
*/
proxy.invokeSuper(o , objects);
System.out.println("--------------------------");
System.out.println("合适,就步入婚礼的殿堂");
return null;
}
}
-
测试类:
public class FindLoveTest { public static void main(String[] args) { ZhangSanFindLove instance = (ZhangSanFindLove)new MyMethodInterceptor().getInstance("gupaoedu.vip.agent.cglib.ZhangSanFindLove"); ZhangSanFindLove instance1 = (ZhangSanFindLove)new MyMethodInterceptor().getInstance(ZhangSanFindLove.class); instance.findLove(); instance1.findLove(); } }
工厂模式
-
1、特点
隐藏复杂的逻辑处理过程,只关心执行结果。 简单工厂、工厂方法、抽象工厂 任督二脉 实现统一管理,专业化管理 如果没有工厂模式,小作坊,没有执行标准的 如果买到三无产品(没有标准) 工厂接口,就定义了所有工厂的执行标准 例: 码农就是执行标准的人 系统架构师,就是制定标准的人 设计模式的经典之处,就在于,解决了编写代码的人和调用代码的人双方的痛处 解决了我们的双手
-
spring中的工厂模式
Bean
BeanFactory(生产Bean)
单例的Bean
被代理过的Bean
最原始的Bean(原型)
List类型的Bean
作用域不同的Bean
getBean
非常的紊乱,维护困难
解耦(松耦合开发)
- 举例
1、公共接口与类:
public interface Car {
void getName(Car car);
}
public class Bmw implements Car{
public void getName(Car car) {
System.out.println("Bmw Car...");
}
}
public class Benz implements Car{
public void getName(Car car) {
System.out.println("Benz Car...");
}
}
public class Audi implements Car{
public void getName(Car car) {
System.out.println("Audi Car...");
}
}
1.1、简单工厂模式:
public class SimpleFactory {
/**
* 通过输入参数判断是什么汽车厂商
* @param name
* @return 汽车厂商
*/
public Car getName(String name){
if(name.equalsIgnoreCase("BMW")){
System.out.println("BMW Car...");
return new Bmw();
}else if(name.equalsIgnoreCase("BENZ")){
System.out.println("BENZ Car...");
return new Benz();
}else if(name.equalsIgnoreCase("AUDI")){
System.out.println("AUDI Car...");
return new Audi();
}else {
System.out.println("没有您要找的汽车生产厂商...");
return null;
}
}
}
public class SimpleFactoryTest {
public static void main(String[] args) {
new SimpleFactory().getName("benz");
}
}
1.2 工厂方法模式:
public interface FuncFactory {
Car getCar();
}
public class BmwFactory implements FuncFactory{
public Car getCar() {
System.out.println("func bmw car ...");
return new Audi();
}
}
public class BenzFactory implements FuncFactory{
public Car getCar() {
System.out.println("func benz car ...");
return new Benz();
}
}
public class AudiFactory implements FuncFactory{
public Car getCar() {
System.out.println("func audi car ...");
return new Audi();
}
}
public class FuncFactoryTest {
public static void main(String[] args) {
FuncFactory factory = new BmwFactory();
factory.getCar();
}
}
1.3 抽象工厂模式:
public abstract class AbstractFactory {
public abstract Car getCar();
/**
* 通过输入参数判断是什么汽车厂商
* @param name
* @return 汽车厂商
*/
public Car getCar(String name){
if(name.equalsIgnoreCase("BMW")){
return new BmwFactory().getCar();
}else if(name.equalsIgnoreCase("BENZ")){
return new BenzFactory().getCar();
}else if(name.equalsIgnoreCase("AUDI")){
return new AudiFactory().getCar();
}else {
System.out.println("没有您要找的汽车生产厂商...");
return null;
}
}
}
public class AudiFactory extends AbstractFactory {
public Car getCar() {
System.out.println("abst audi car ...");
return new Audi();
}
}
public class BenzFactory extends AbstractFactory {
public Car getCar() {
System.out.println("abst benz car ...");
return new Benz();
}
}
public class BmwFactory extends AbstractFactory {
public Car getCar() {
System.out.println("abst bmw car ...");
return new Audi();
}
}
public class DEfaultFactory extends AbstractFactory{
private static final BenzFactory factory = new BenzFactory();
public Car getCar() {
return factory.getCar();
}
}
public class AbstractFactoryTest {
public static void main(String[] args) {
DEfaultFactory factory = new DEfaultFactory();
factory.getCar("bmw");
}
}
单例模式
2WH(人都是天生的惰性)
-
穷举法:
配置文件:如果不是单例(针对于某一种功能的配置) (两个配置文件中的内容一样的,则有一个是浪费的 如果是不一样的,我们就不知道以哪个为准了) 直接上级领导:(对于你来说,如果有多个领导,你到底听谁的? 选择恐惧症) 日历:(不严谨)在中国,是有两种日历同时存在的 阴历(农历,一般用于指导农业生产,二十四节气) 和阳历(公历,一般用于国际交流、企事业单位的工作指导) (在万千世界中,即使是一片小小的树叶,他们都是长得不一样的) 是什么?为什么要有单例模式?单例具体怎么实现?
-
特点:
1、保证从系统启动到系统终止,全过程只会产生一个实例。 2、当我们在应用中遇到功能性冲突的时候,需要使用单例模式。
常用写法:
public class Singleton1 {
//私有化构造
private Singleton1(){}
//定义一个内部类,用于对象的返回
private static final class LazyLoadler {
private static final Singleton1 INSTANCE = new Singleton1();
}
public static Singleton1 getInstance(){
return LazyLoadler.INSTANCE;
}
}
委派模式
要和代理模式区分开来
-
2WH,和代理模式区分开来,什么是2WH?
What:两个角色,受托人,委托人(社会上是平等关系) 公司里面:项目经理,普通员工(法律上平等的,工作的关系,各自的职责会不一样) 干活是我的,功劳是你的(最重要的特点) 项目经理(委托人):主要职责是安排任务 普通员工(受托人):执行任务
-
特点:
1、类似于中介的功能(委托机制); 2、持有被委托人的引用。 3、不关心过程,只关心结果。 Why? 主要目的就是隐藏具体实现逻辑 IOC 容器中,有一个 Register 的东西(为了告诉我们的容器,在这个类被初始化的过程中,需要做很多 不同的逻辑处理,需要实现多个任务执行者,分别实现各自的功能) 保证结果的多样性,对于用户来是只有一种方法
-
举例:
/** * @Author: Steven.yu * @Description: 执行者接口 * @CreateTime: 2020/08/31 14:15:04 */ public interface IExecutor { void doing(); } public class Executor1 implements IExecutor { public void doing() { System.out.println("我是员工1"); } } public class Executor2 implements IExecutor { public void doing() { System.out.println("我是员工2"); } } public class ManagerExecutor implements IExecutor{ private static IExecutor executor; public ManagerExecutor(IExecutor executor){ this.executor = executor; } public void doing() { this.executor.doing(); } } public class ExecutorTest { public static void main(String[] args) { ManagerExecutor managerExecutor = new ManagerExecutor(new Executor1()); managerExecutor.doing(); } }
策略模式
概念:过程不同,但结果一样。
原型模式
概念:数据内容完全一样,但实例不同。
就是一个现成的对象,这个对象里面有已经设置好的值
当我要新建一个对象,并且要给新建的对象赋值,而且赋值内容要分之前的一模一样。
能够直接拷贝其实际内容的数据类型/只支持9种,8大基本类型和String,浅拷贝。
-
举例:
/** * @Author: Steven.yu * @Description: 金箍棒实体 * @CreateTime: 2020/09/02 15:14:08 */ package com.gupaoedu.vip.prototype; import java.io.Serializable; public class GoldenCudgel implements Serializable { /** * 高度 */ private Integer height; /** * 直径 */ private Integer diameter; public Integer getHeight() { return height; } public void setHeight(Integer height) { this.height = height; } public Integer getDiameter() { return diameter; } public void setDiameter(Integer diameter) { this.diameter = diameter; } /** * 金箍棒长大 */ public void graw(){ this.diameter *= 2; this.height *= 2; } /** * 金箍棒缩小 */ public void narrow(){ this.diameter /= 2; this.height /= 2; } } public class Monkey implements Serializable { /** * 姓名 */ private String name; /** * 年龄 */ private Integer age; /** * 出生日期 */ private Date date; public Monkey() { } public Monkey(String name, Integer age, Date date) { this.name = name; this.age = age; this.date = date; } 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 Date getDate() { return date; } public void setDate(Date date) { this.date = date; } } /** * @Author: Steven.yu * @Description: 齐天大圣 * @CreateTime: 2020/09/02 15:18:51 */ package com.gupaoedu.vip.prototype; import java.io.*; import java.util.Date; public class GreatSage extends Monkey implements Cloneable,Serializable{ /** * 金箍棒 */ private GoldenCudgel cudgel; public GoldenCudgel getCudgel() { return cudgel; } public void setCudgel(GoldenCudgel cudgel) { this.cudgel = cudgel; } public GreatSage(){ this.setName("yuhai"); this.setAge(22); this.setDate(new Date()); } public void change(){ System.out.println("大圣本尊的出生日期是:" + this.getDate().getTime()); GreatSage clone = (GreatSage)this.clone(); System.out.println("克隆大圣的出生日期是:" + clone.getDate().getTime()); System.out.println("大圣本尊和克隆大圣是否为同一个对象:" + (this == clone)); System.out.println("大圣本尊的金箍棒和克隆大圣的金箍棒是否为同一个对象:" + (this.cudgel == clone.cudgel)); } @Override protected Object clone() { ByteArrayOutputStream baos = null; ObjectOutputStream oos = null; ByteArrayInputStream bais = null; ObjectInputStream ois = null; try { baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(this); bais = new ByteArrayInputStream(baos.toByteArray()); ois = new ObjectInputStream(bais); GreatSage greatSage = (GreatSage)ois.readObject(); greatSage.setDate(new Date()); greatSage.setCudgel(new GoldenCudgel()); return greatSage; } catch (Exception e) { return null; }finally { try{ oos.close(); baos.close(); ois.close(); bais.close(); }catch (Exception e){ } } } } public class GreatSageTest { public static void main(String[] args) { GreatSage greatSage = new GreatSage(); greatSage.change(); } }
模板模式
概念:执行流程固定,但中间有些步骤有细微差别。
-
举例:
public abstract class Water { public void print(){ mainMaterials(); System.out.println("加入100°的沸水,泡2-3分钟"); accessories(); System.out.println("开始品尝"); } /** * 准备主料 */ public abstract void mainMaterials(); /** * 准备辅料 */ public abstract void accessories(); } public class GreenTea extends Water { public void mainMaterials() { System.out.println("准备绿茶茶叶..."); } public void accessories() { System.out.println("清理绿叶..."); } } public class MilkTea extends Water { public void mainMaterials() { System.out.println("准备优乐美奶茶..."); } public void accessories() { System.out.println("加入辅料..."); } } public class WaterTest { public static void main(String[] args) { Water water = new MilkTea(); water.print(); } }