昨天写的四种建造者的设计模式是在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 {
@Override
public 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;
}
@Override
public 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 {
@Override
public 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方法,代理方法
@Override
public 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的流程。