昨天写的四种建造者的设计模式是在spring中用BeanDefinitionBuilder来动态构建bean定义对象时创建的在IOC容器中,所有的操作都是基于bean对象来操作的,在spring中用的是深拷贝的模式,spring中常用的设计模式是13种,还有一种设计模式是桥接的设计模式,主要用到泛型的会用到。
结构型设计模式:
1、代理设计模式:当我们看spring的aop的时候会用到代理设计模式,主要用来创建bean的代理对象的,因为aop的核心是进行横切,本质将bean定义的对象,然后创建一个代理对象,
来以偷听换玉的方式将bean的定义对象换成代理对象,然后这个容器种中bean本身的对象就不存在了,全部由代理对象来操作,@Autowired和@Resource在依赖注入的时候,全部注入的是aop代理对象,在代理设计模式中一种是jdk的,一种是cglib的,在spring中大多数都是cglib代理,代理就是代理别人的功能。
1.1、JdkDynamicAopProxy :jdk动态代理,用来创建接口代理对象
1.2、CglibAopProxy:动态代理,用来创建类的代理对象
静态代理:
①、首先创建一个接口:
package com.weizhaoyang.proxy;/*** 业务服务接口*/public interface DemoService{/*** 业务服务demo*/publicString demo();/*** 业务服务2*///public void demo2();}
②、创建一个实现类:
package com.weizhaoyang.proxy;public class DemoServiceImpl implements DemoService {@Overridepublic String demo(String name) {System.out.println("我需要记录日志");return "weizhaoyang";}}
创建一个静态代理的类:
package com.weizhaoyang.proxy;/*** DemoService的静态代理**/public class DemoServiceStaticProxy implements DemoService {//加一个属性DemoService,全部由代理类来控制掉,所以要依赖进来,也就是一种封装,只由代理类来控制private DemoService demoService;public DemoServiceStaticProxy(DemoService demoService){this.demoService=demoService;}@Overridepublic String demo(String name) {System.out.println("代理执行之前");demoService.demo(name);System.out.println("代理执行之后");return "weizhaoyang";}}
创建一个测试类:
package com.weizhaoyang.proxy;public class DemoTest1 {public static void main(String[] args) {DemoService demoService= new DemoServiceImpl();//创建一个代理类的对象,来把demoService这个对象给 控制住DemoService demoService2=new DemoServiceStaticProxy(demoService);//然后再DemoService这个接口之上完成自己的功能System.out.println(demoService2.demo("weizhaoyang"));}}
运行的结果如下:
在Spring的ioc容器里面相当于用这个代理对象将DemoService对象全部替换掉了,这就是代理对象能代替对象的根本原因。
缺点:
1、静态代理必须要依赖原有的对象
2、每加一个需求都需要改三个地方,接口,实现类,代理类,不好维护。
在java中一个代理类只能控制一个行为
解决上面的缺点:
1、通过反射动态代理就是基于反射来操作的,通过Method来动态执行接口中所有的方法,就是把接口中的方法抽象成一个Method对象传进来操作,反射虽然效率不高,但是提高了代码的灵活性。
2、用jdk动态代理来实现,就是基于反射来实现的,让类来实现InvocationHandler,通过代理对象调用invoke方法
代码如下:首先提供一个抽象的业务接口,把这个接口可以当作成service,也可以当作成具体的对象。
package com.weizhaoyang.proxy;/*** 业务服务接口*/public interface DemoService{/*** 业务服务demo*/publicString demo();}
提供 一个实现类:我这个行为需要产生日志记录
package com.weizhaoyang.proxy;public class DemoServiceImpl implements DemoService {@Overridepublic String demo(String name) {System.out.println("我需要记录日志");return "weizhaoyang";}}
提供一个动态代理的类:
package com.weizhaoyang.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.sql.SQLOutput;/*** InvocationHandler执行处理器*/public class DemoServiceProxy implements InvocationHandler {//依赖目标类private DemoService demoService;public DemoServiceProxy(DemoService demoService) {this.demoService=demoService;}public Object getProxy(){return Proxy.newProxyInstance(DemoService.class.getClassLoader(),new Class[]{DemoService.class},this);}//通过反射委托调用执行invoke方法,代理方法@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//记录开始日志System.out.println("方法执行前打印日志");//开始执行方法,调用自己的方法Object object= null;try {object = method.invoke(demoService,args);} catch (RuntimeException e) {e.getMessage();}//3、记录日志System.out.println("方法执行后打印日志");if(object.equals("weizhaoyang")){System.out.println("方法返回值通知");throw new RuntimeException("异常通知");}return object;}}
写个测试类:
package com.weizhaoyang.proxy;public class DemoTest1 {public static void main(String[] args) {/* DemoService demoService= new DemoServiceImpl();//创建一个代理类的对象,来把demoService这个对象给 控制住DemoService demoService2=new DemoServiceStaticProxy(demoService);//然后再DemoService这个接口之上完成自己的功能System.out.println(demoService2.demo());*///创建被代理对象DemoService demoService=new DemoServiceImpl();//创建代理的对象DemoServiceProxy demoServiceProxy=new DemoServiceProxy(demoService);//获取被代理的对象DemoService service= (DemoService) demoServiceProxy.getProxy();service.demo("weizhaoyang");}}
运行的结果如下:
解释下、getProxy方法中的参数的作用:
方法中的参数:new Class[]{DemoService.class}:把接口当作参数传进去 this:代表传InvocationHandler对象, DemoService.class.getClassLoader():将类加载器传进来,类加载器可以自定义,防止在定义接口的时候防止不是默认的加载器来加载道jvm里面的,所以需要传classloader ,InvocationHandler通过它来做一个桥梁将代理类和被代理做一个组合起来,然后将代理类对象去执行invoke方法,来动态的去调用本身的方法。
总结:
1、spring的aop就是基于上面的本质来操作的,所以在aop之中有前置通知,和后置通知还有方法返回值(执行完成之后,方法返回值没有返回)之后通知,还有一种是抛异常通知,可以在返回值之后抛异常,而在spring中把这几个通知封装成了各个的接口,封装的接口的意义在于去扩展,环绕通知是针对上面的四种一整套,前置通知和后置通知只是针对于方法的执行前后,这是jdk的动态的一种思路。
2、下面的就称之为springAOP中的抽象为前置通知。
下面的就称之为springAOP中的抽象为后置通知。
下面的就称之为springAOP中的抽象为异常通知。
下面的就称之为springAOP中的抽象为方法的返回值通知。
这个就称之为springAOP连接点joinPoint
这个就是SpringAop中的切入点,每一个切入点通过连接点来进行切入
然后把切点和通知封装为切面对象advice,然后动态的去植入,这就是aop的流程。