1、什么是代理模式
代理:自己不做,找别人帮你做
代理模式:在一个原有功能的基础上添加新的功能
分类:静态代理和动态代理
2、静态代理
原有方式:就是将核心业务和服务方法都编写在一起
java
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基于类的静态代理
将服务型代码分离出来,核心业务--保存业务中只有保存功能
java
package com.AE.service;
public class TeamService{
public void add() {
System.out.println("TeamService---add-----"); // 核心业务
}
}
java
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("回滚事务");
}
}
}
使用:
java
public static void main(String[] args) {
TeamService ser=new ProxyTeamService();
ser.add();
}
这种基于类的静态代理最大的问题就是代理类之呢个代理一个类。
2.2、基于接口的静态代理
为核心业务(保存add)创建一个接口,通过接口暴露被代理的方法
要求:代理类和被代理类都实现了同一个接口
java
package com.AE;
/**
* 接口定义核心方法
*/
public interface IService {
void add();
}
java
package com.AE;
public class TeamService implements IService{
@Override
public void add(){
System.out.println("TeamService---- add----");// 核心业务
}
}
package com.AE;
public class UserService implements IService{
@Override
public void add() {
System.out.println("UserService---- add-----");
}
}
java
package com.AE;
/**
* 基于接口的静态代理:
* 代理类和被代理类实现同一个接口
*/
public class ProxyTranService implements IService {
private IService service;//被代理的对象
public ProxyTranService(IService service) {
this.service = service;
}
@Override
public void add() {
try {
System.out.println("开始事务");
service.add();//核心业务就是由被代理对象完成 ;其他服务功能由代理类完成
System.out.println("提交事务");
}catch (Exception e){
System.out.println("回滚事务");
}
}
}
java
package com.AE;
public class ProxyLogService implements IService {
private IService service;//被代理对象
public ProxyLogService(IService service) {
this.service = service;
}
@Override
public void add() {
try {
System.out.println("开始日志");
service.add();//核心业务就是由被代理对象完成 ;其他服务功能由代理类完成
System.out.println("结束日志");
}catch (Exception e){
System.out.println("异常日志");
}
}
}
测试类:
java
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代码提取出来
java
package com.AE;
/**
* 切面:服务代码,切入到核心代码中,切入到哪里,给了四个位置
*/
public interface AOP {
void before();
void after();
void exception();
void myFinally();
}
java
package com.AE;
public class TranAOP implements AOP {
@Override
public void before() {
System.out.println("事务----before");
}
@Override
public void after() {
System.out.println("事务----after");
}
@Override
public void exception() {
System.out.println("事务----exception");
}
@Override
public void myFinally() {
System.out.println("事务----myFinally");
}
}
java
package com.AE;
public class LogAop implements AOP{
@Override
public void before() {
System.out.println("日志----before");
}
@Override
public void after() {
System.out.println("日志----after");
}
@Override
public void exception() {
System.out.println("日志----exception");
}
@Override
public void myFinally() {
System.out.println("日志----myFinally");
}
}
java
package com.AE
public class ProxyAOPService implements IService {
private IService service;//被代理对象
private AOP aop;//要加入切面
public ProxyAOPService(IService service, AOP aop) {
this.service = service;
this.aop = aop;
}
@Override
public void add() {
try {
aop.before();
service.add();//被代理对象干活
aop.after();
}catch (Exception e){
aop.exception();
}finally {
aop.myFinally();
}
}
}
测试类:
java
@Test
public 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、直接编写
java
/**
* 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() {
@Override
public 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,并且使用切面来简化。
java
public class ProxyHandler implements InvocationHandler {
private IService service;// 被代理对象、目标对象
private AOP aop;
public ProxyHandler(IService service, AOP aop) {
this.service = service;
this.aop = aop;
}
@Override
public 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();
}
}
}
然后只需要将被代理类和切面类传进去即可,然后通过动态返回的代理类进行核心业务的执行。
java
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());
}
方式二
再次简化代码的编写,因为可以直接获取动态返回的代理类,因为参数都可以通过被代理类和切面类得到。
java
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() {
@Override
public 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();
}
}
}
);
}
}
然后通过返回的代理类进行核心业务的执行,然后假如有多个服务代码进行,则可以通过二次代理进行使用。
java
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、代码编写
java
public class NBAService {
public int add(String name,int id){
System.out.println("NBAService---- add----");
return id;
}
}
java
public static void main(String[] args) {
//目标对象:没有接口
NBAService nbaService=new NBAService();
//创建代理对象:选择cglib动态代理
NBAService proxyService= (NBAService) Enhancer.create(nbaService.getClass(),
new MethodInterceptor() {//回调函数编写代理规则
@Override
public 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、结构化设计
java
public class CglibProxyFactory {
public Object getProxyInstance(NBAService nb, AOP aop) {
// cglib代理
return Enhancer.create(nb.getClass(), new MethodInterceptor() {
@Override
public 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;
}
});
}
}
java
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());
}