1、什么是代理模式
代理:自己不做,找别人帮你做
代理模式:在一个原有功能的基础上添加新的功能
分类:静态代理和动态代理
2、静态代理
原有方式:就是将核心业务和服务方法都编写在一起
package com.AE.service;public class TeamService{public void add() {try {System.out.println("开始事务");System.out.println("TeamService---add-----");System.out.println("提交事务");} catch (Exception e) {e.printStackTrace();System.out.println("事务回滚");}}
}
2.1基于类的静态代理
将服务型代码分离出来,核心业务--保存业务中只有保存功能
package com.AE.service;public class TeamService{public void add() {System.out.println("TeamService---add-----"); // 核心业务}
}
import com.AE;/*** 基于类的静态代理:* 要求继承被代理的类* 弊端:每次只能代理一个类*/
public class ProxyTeamService extends TeamService {public void add(){try {System.out.println("开始事务");super.add();//核心业务就是由被代理对象完成 ;其他服务功能由代理类完成System.out.println("提交事务");}catch (Exception e){System.out.println("回滚事务");}}
}
使用:
public static void main(String[] args) {TeamService ser=new ProxyTeamService();ser.add();}
这种基于类的静态代理最大的问题就是代理类之呢个代理一个类。
2.2、基于接口的静态代理
为核心业务(保存add)创建一个接口,通过接口暴露被代理的方法
要求:代理类和被代理类都实现了同一个接口
package com.AE;
/*** 接口定义核心方法*/
public interface IService {void add();
}
package com.AE;
public class TeamService implements IService{@Overridepublic void add(){System.out.println("TeamService---- add----");// 核心业务}
}package com.AE;
public class UserService implements IService{@Overridepublic void add() {System.out.println("UserService---- add-----");}
}
package com.AE;
/*** 基于接口的静态代理:* 代理类和被代理类实现同一个接口*/
public class ProxyTranService implements IService {private IService service;//被代理的对象public ProxyTranService(IService service) {this.service = service;}@Overridepublic void add() {try {System.out.println("开始事务");service.add();//核心业务就是由被代理对象完成 ;其他服务功能由代理类完成System.out.println("提交事务");}catch (Exception e){System.out.println("回滚事务");}}
}
package com.AE;public class ProxyLogService implements IService {private IService service;//被代理对象public ProxyLogService(IService service) {this.service = service;}@Overridepublic void add() {try {System.out.println("开始日志");service.add();//核心业务就是由被代理对象完成 ;其他服务功能由代理类完成System.out.println("结束日志");}catch (Exception e){System.out.println("异常日志");}}
}
测试类:
public static void main(String[] args) {TeamService teamService=new TeamService();//被代理对象UserService userService=new UserService();//被代理对象ProxyTranService tranService=new ProxyTranService(userService);//事务代理对象--一级代理//tranService.add();//代理对象干活ProxyLogService logService=new ProxyLogService(tranService);//日志的代理对象--二级代理logService.add();}
2.3、提取出切面代码,作为AOP接口
就是将业务前后执行的代码,以及异常后执行代码和finally代码提取出来
package com.AE;/*** 切面:服务代码,切入到核心代码中,切入到哪里,给了四个位置*/
public interface AOP {void before();void after();void exception();void myFinally();
}
package com.AE;
public class TranAOP implements AOP {@Overridepublic void before() {System.out.println("事务----before");}@Overridepublic void after() {System.out.println("事务----after");}@Overridepublic void exception() {System.out.println("事务----exception");}@Overridepublic void myFinally() {System.out.println("事务----myFinally");}
}
package com.AE;
public class LogAop implements AOP{@Overridepublic void before() {System.out.println("日志----before");}@Overridepublic void after() {System.out.println("日志----after");}@Overridepublic void exception() {System.out.println("日志----exception");}@Overridepublic void myFinally() {System.out.println("日志----myFinally");}
}
package com.AEpublic class ProxyAOPService implements IService {private IService service;//被代理对象private AOP aop;//要加入切面public ProxyAOPService(IService service, AOP aop) {this.service = service;this.aop = aop;}@Overridepublic void add() {try {aop.before();service.add();//被代理对象干活aop.after();}catch (Exception e){aop.exception();}finally {aop.myFinally();}}
}
测试类:
@Testpublic void test02(){IService teamService=new TeamService();//被代理对象--核心内容AOP logAop=new LogAop();//切面-服务内容AOP tranAop=new TranAOP();IService service=new ProxyAOPService(teamService,logAop); //代理对象--一级代理IService service2=new ProxyAOPService(service,tranAop);//代理对象--二级代理service2.add();}
2.4、静态代理总结
1、在不修改目标对象的功能前提下,对目标对象功能扩展
2、缺点:因为代理对象,需要与目标对象实现一样的接口。所以会有很多代理类,类太多。一旦接口增加方法,目标对象与代理对象都要维护。
3、动态代理
静态代理:要求代理类一定存在
动态代理:程序运行的时候,根据要被代理的对象动态生成代理类,省去代理类的编写。
类型:1、基于JDK的动态代理
2、基于CGLIB的动态代理
有接口就用JDK的动态代理,没有就用CGLIB的动态代理
3.1、基于JDK的动态代理
3.1.1、直接编写
/*** newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)* ClassLoader :类加载器,因为动态代理类,借助别人的类加载器。一般使用被代理对象的类加载器。* Class<?>[] interfaces:接口类对象的集合,针对接口的代理,针对哪个接口做代理,一般使用的就是被代理对象的接口。* InvocationHandler:句柄,回调函数,编写代理的规则代码* * public Object invoke(Object arg0, Method arg1, Object[] arg2)* Object arg0:代理对象* Method arg1:被代理的方法* Object[] arg2:被代理方法被执行的时候的参数的数组*/
public static void main1(String[] args) {TeamService teamService = new TeamService();// 被代理对象// JDK提供的IService proxyService = (IService) Proxy.newProxyInstance(teamService.getClass().getClassLoader(),teamService.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {System.out.println("开始事务");Object invoke = method.invoke(teamService, args); // 核心业务System.out.println("提交事务");return invoke;} catch (Exception e) {e.printStackTrace();System.out.println("回滚事务");} finally {System.out.println("finally---");}return null;}});proxyService.add();System.out.println(teamService.getClass());System.out.println(proxyService.getClass());}
3.1.2、结构化设计
方式一
提前写好InvocationHandler,并且使用切面来简化。
public class ProxyHandler implements InvocationHandler {private IService service;// 被代理对象、目标对象private AOP aop;public ProxyHandler(IService service, AOP aop) {this.service = service;this.aop = aop;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {aop.before();Object invoke = method.invoke(service, args); // 核心业务aop.after();return invoke;} catch (Exception e) {e.printStackTrace();aop.exception();throw e;} finally {aop.myFinally();}}
}
然后只需要将被代理类和切面类传进去即可,然后通过动态返回的代理类进行核心业务的执行。
public static void main2(String[] args) {// 目标对象IService teamService = new TeamService();// 准备切面AOP aop = new TranAop();IService service = (IService) Proxy.newProxyInstance(teamService.getClass().getClassLoader(),teamService.getClass().getInterfaces(),new ProxyHandler(teamService, aop));service.add();System.out.println(service.getClass());}
方式二
再次简化代码的编写,因为可以直接获取动态返回的代理类,因为参数都可以通过被代理类和切面类得到。
public class ProxyFactory {private IService service;private AOP aop;public ProxyFactory(IService service, AOP aop) {this.service = service;this.aop = aop;}/*** 获取动态代理对象的实例*/public Object getProxyInstance(){return Proxy.newProxyInstance(service.getClass().getClassLoader(),service.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {aop.before();Object invoke = method.invoke(service, args); // 核心业务aop.after();return invoke;} catch (Exception e) {e.printStackTrace();aop.exception();throw e;} finally {aop.myFinally();}}});}
}
然后通过返回的代理类进行核心业务的执行,然后假如有多个服务代码进行,则可以通过二次代理进行使用。
public static void main(String[] args) {// 目标对象IService teamService = new TeamService();// 准备切面AOP aop = new TranAop();AOP logAop = new LogAop();// 获取代理对象IService service = (IService) new ProxyFactory(teamService, aop).getProxyInstance();IService service1 = (IService) new ProxyFactory(service, logAop).getProxyInstance();service1.add();}
3.2、基于CGLIB的动态代理
Cglib代理,也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展。
-
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB实现。
-
CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception。
-
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉
3.2.1、代码编写
public class NBAService {public int add(String name,int id){System.out.println("NBAService---- add----");return id;}
}
public static void main(String[] args) {//目标对象:没有接口NBAService nbaService=new NBAService();//创建代理对象:选择cglib动态代理NBAService proxyService= (NBAService) Enhancer.create(nbaService.getClass(),new MethodInterceptor() {//回调函数编写代理规则@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {try {System.out.println("开始事务");Object invoke = methodProxy.invokeSuper(o, objects);//核心System.out.println("提交事务");return invoke;}catch (Exception e){System.out.println("事务回滚");throw e;}finally {System.out.println("finally------------");}}});//代理对象干活int res=proxyService.add("AE",12);System.out.println(res);}
3.2.2、结构化设计
public class CglibProxyFactory {public Object getProxyInstance(NBAService nb, AOP aop) {// cglib代理return Enhancer.create(nb.getClass(), new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {try {aop.before();Object o1 = methodProxy.invokeSuper(o, objects);aop.after();return o1;} catch (Exception e) {aop.exception();e.printStackTrace();} finally {aop.myFinally();}return null;}});}
}
public static void main(String[] args) {NBAService nb = new NBAService();// 没有接口的目标对象AOP aop = new TranAop();// 创建切面// 创建代理对象:选择CGLIB动态代理NBAService proxyInstance = (NBAService) new CglibProxyFactory().getProxyInstance(nb, aop);int ae = proxyInstance.add("AE", 12);System.out.println(ae);System.out.println(proxyInstance.getClass());}