Spring框架关于IOC/DI与AOP所使用的设计模式

您所在的位置:网站首页 download是什么模式 Spring框架关于IOC/DI与AOP所使用的设计模式

Spring框架关于IOC/DI与AOP所使用的设计模式

2024-07-07 06:42| 来源: 网络整理| 查看: 265

IOC与AOP所使用的设计模式 1.控制反转(IOC)和依赖注入(DI)1.1工厂设计模式2.1单例模式 2.面向切面编程(AOP)2.1代理模式(proxy-pattern) 在使用Spring框架的过程中,IOC/DI和AOP就是Spring框架的灵魂和核心。 主要用到的设计模式有工厂模式和代理模式。 IOC就是典型的工厂模式,通过sessionfactory去注入实例。 AOP就是典型的代理模式的体现。

1.控制反转(IOC)和依赖注入(DI)

IOC(inversion of control, 控制反转):是一种设计思想,而不是一种技术。这里的控制指把控制权从应用程序中剥离出来。ioc它可以把创建对象和查找依赖对象的权限交给Ioc容器控制,而不是传统的由这些对象的使用方(消费者)进行创建初始化操作。IoC是一种让服务消费者不直接依赖于服务提供者的组件设计方式,是一种减少类与类之间依赖的设计原则。 DI(Dependency Injection, 依赖注入):是IOC思想的一种实现。 它负责实现IOC动态地向某个对象提供它所需要的其他对象.,比如一个人需要一根扫把, 不是由这个人自己去做扫把, 而是由Spring将做好的扫把给他, 而这个人全程需要做的,就是喊我要一根扫把. 什么叫做依赖, 人需要扫把, 人就对扫把有了依赖. 而DI就是根据这个依赖,将扫把分配给这个人的.

1.1工厂设计模式

工厂模式是将将创建对象的责任转移到工厂类。 场景:中午吃午餐,提供的食物有:fastfood,noodles,hamburger 对象:人,FastFood,Noodles,Hamburger,提供服务service() 实现一:传统方法实现 1.食物类对象提供服务

public class FastFood { public void service() { System.out.println("麻婆豆腐盖浇饭..."); } } public class Noodles{ public void service() { System.out.println("大盘鸡拌面..."); } } public class Hamburger{ public void service() { System.out.println("牛肉汉堡..."); } }

2.人对象选择食物

public class Person { public void eat() { Noddles service = new Noddles(); service.service(); } }

实现一的问题: 1.Noddles service = new Noddles(); 确定了对象的类型,替换类型,就要替换实例对象。 2.针对具体的开发并不稳定 实现二:实现一的改进,面向接口的开发 1.创建接口,统一规范

public interface IService { void service(); }

2.使用统一接口,规范服务

public class FastFood implements IService{ @Override public void service() { System.out.println("麻婆豆腐盖浇饭..."); } } public class Noodles implements IService{ @Override public void service() { System.out.println("大盘鸡拌面..."); } } public class Hamburgerimplements IService{ @Override public void service() { System.out.println("牛肉汉堡..."); } }

3.人对象选择食物

public class Person { public void eat() { IService service = new Noddles(); service.service(); } }

实现二的问题: Person需要service服务时Noodles出现,Person对象与Noodles()具有依赖性 实现三:职责分离,解除依赖。使用工厂类来管理对象 1.工厂类

public class FoodFactory { public static IService create(int index) { switch (index) { case 1: return new FastFood(); case 2: return new Hamburger(); default: break; } return new Noddles(); } }

2.人选择食物

@Test public void test() { Person 小王= new Person(); 小王.eat(2); }

改进工厂:利用反射机制创建顾客想要的食物 1.创建一个菜单,顾客将想要选择的食物写到菜单上(FastFood,Noodles,Hamburger),顾客想修改食物,直接在菜单修改即可。 在这里插入图片描述 2.工厂类读取菜单并返回食物对象

public class FoodFactory { public static IService create() { IService is= null; try { BufferedReader in = new BufferedReader(new FileReader("src/menu.txt")); String line = in.readLine();\ is = (IService) Class.forName("com.yang.entity."+line).newInstance(); } catch (Exception e) { e.printStackTrace(); } return is; } }

3.人进行吃饭服务

public class TestFactory { @Test public void test() { Person 小王= new Person(); 小王.eat(); } }

工厂设计模式的优点: 1.面向接口编程,体现了面向对象的思想; 2.将创建对象的工作转移到了工厂类; 工厂模式应用范围:

创建对象—》new

创建对象比较复杂的业务

SqlSessionFactory–mybatis

BeanFactory —spring

ApplicationContext—>spring

工厂模式升级:

由框架创建工厂对象由工厂(容器)进行管理业务需要什么,工厂根据业务依赖自动注入–好莱坞原则 2.1单例模式

单例模式

2.面向切面编程(AOP)

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。 AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

一.AOP的基本概念

Aspect(切面):通常是一个类,里面可以定义切入点和通知JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,aroundPointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

通知方法:

前置通知:在我们执行目标方法之前运行(@Before)后置通知:在我们目标方法运行结束之后 ,不管有没有异常(@After)返回通知:在我们的目标方法正常返回值后运行(@AfterReturning)异常通知:在我们的目标方法出现异常后运行(@AfterThrowing)环绕通知:动态代理, 需要手动执行joinPoint.procced()(其实就是执行我们的目标方法执行之前相当于前置通知, 执行之后就相当于我们后置通知(@Around)

二.Spring AOP Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。

2.1代理模式(proxy-pattern)

代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。 场景描述:房东准备出租自己的房子,没有时间找中介帮助出租房子 对象:房东(Real Object),中介(Proxy Object) 静态代理 核心:接口 1.声明租房接口

public interface IRent(){ void rent(); }

2.房东实现租房接口

public class HouseKeeper implements IRent{ @Override public void rent(){ system.out.println("我有一套三居室出租,租金1500元"); } }

3.中介基于房东的需求实现租房借口

public class HouseAgent implements IRent{ private IRent rent; public HouseAgent(IRent rent){ this,rent=rent; } @Override public void rent(){ before(); this,rent.rent(); after(); } private void before(){ system.out.println("每月物业费收取100元"); } private void after(){ system.out.println("转租额外收一个月房租"); } }

4.租客看到的租房信息

@Test public void test(){ IRent house = new HouseAgent(new HouseKeeper()); house.rent(); }

缺点:代理对象随着接口的变化而变化 动态代理 实现InvocationHandler(产生代理对象的类)

public class HouseProxy implements InvocationHandler { private Object real; public HouseProxy(Object real) { this.real = real; } /** * 产生代理对象 * @return */ public Object createProxy() { return Proxy.newProxyInstance(this.real.getClass().getClassLoader(), this.real.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object retVal = method.invoke(this.real, args);//real对象调用method方法,传入参数args,retVal方法的返回值 after(); return retVal; } private void before() { System.out.println("我来了,准备工作..."); } private void after() { System.out.println("工作完成,走人...."); } }

Proxy.newProxyInstance()—产生代理对象

IRent rent =(IRent) new HouseProxy(new HouseKeeper()).createProxy(); rent.xuequ(); 优点: 可以随着接口的变化而变化。缺点: 依赖于接口

CGLIB代理 不使用接口实现代理, 面向的继承原则

public class CGLIBProxy implements MethodInterceptor { private Object real; public CGLIBProxy(Object real) { this.real = real; } public Object createProxy() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.real.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("我来了...."); Object retVal = proxy.invokeSuper(obj, args); System.out.println("我走了..."); return retVal; } } HouseKeeper hs = (HouseKeeper) new CGLIBProxy(new HouseKeeper()).createProxy(); hs.rent();

CGLIB代理总结: CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3