【Java】Proxy动态代理案例
One:一些相关的笔记
1、关于接口的default关键字
java1.8 接口组成更新,接口新增默认方法,关键字“default”,默认方法在接口的实现类中,不强制重写,但是也可以被重写,而且在接口中,默认方法可以有方法体内容。如果实现类没有重新默认方法,但是会继承这个默认方法,所以创建实现类对象后,可以调用默认方法。
注意事项:
1、当一个实现类实现了多个接口,多个接口里都有相同的默认方法时,实现类必须重写该默认方法,否则编译错误。(a.实现类自己重写逻辑。b. 实现类使用super关键字指定使用哪个接口的默认方法)
2、接口静态方法,接口中支持静态方法,将默认方法的关键字换成static即可。
3、继承类可以直接使用接口中的static方法,也可以创建对象后使用接口中的default方法。
2、代理与代理的几种方式
静态代理:提供服务的接口 <= 接口的代理类(增加切面实现功能添加) <= 各类业务功能
动态代理:提供服务的接口 <= 接口实现类(各类业务功能) <= 代理类(内部包含业务切面)
实现代理的几种方式:
1、业务与切面耦合在一起
2、子类代理实现切面功能增强
3、使用静态代理分离业务
4、使用静态代理分离业务和切面(在静态代理的基础上,将业务切面分离到独立的切面接口,然后针对接口实现不同的事务切面,最后在代理中调用事务切面,进而实现分离业务和切面)
5、使用动态代理优化业务和切面的耦合(重点)
3、关于AOP的一些术语
切面:重复的、公共的、通用的功能。
连接点:即目标方法,因为在目标方法中要实现目标方法的功能和切面功能。
切入点:指定切入的位置,多个连接点构成切入点。切入点可以是一个目标方法/一个类的所有方法/某个包下的所有类的方法。
目标对象:被操作的对象。
通知:指定切入的时机,在目标方法执行前还是执行后还是出错时,还是环绕目标方法切入的切面功能。
Two:一个案例
简介:当前有Service接口提供采购服务(buy)与售后服务(afterSales), 现针对Service接口实施动态代理代理,并且在代理的同时通过AOP接口(aopService)增添对采购服务与售后服务的切面事务(before、after、rollback)。具体效果如图所示:
1、目录结构
2、案例源码
(1)Service.java
package com.Etui.dynamicProxy;
public interface Service {
// 购买服务
void buy();
// 售后服务
default String afterSales(Integer id){return "售后服务…………………………" + id ;};
}
(2)BookServiceImpl.java
package com.Etui.dynamicProxy;
public class BookServiceImpl implements Service {
@Override
public void buy() {
System.out.println("图书购买服务………………");
}
@Override
public String afterSales(Integer id) {
System.out.println("售后服务被调用……………………");
return "Success";
}
}
(3)AopService.java
package com.Etui.dynamicProxy.aop;
public interface AopService {
// 事务开启
default void before() {}
// 事务关闭
default void after() {}
// 事务回滚
default void rollback() {}
}
(4)AopServiceImpl.java
package com.Etui.dynamicProxy.aop;
public class AopServiceImpl implements AopService {
@Override
public void before() {
System.out.println("事务开启…………………………");
}
@Override
public void after() {
System.out.println("事务关闭…………………………");
}
@Override
public void rollback() {
System.out.println("事务回滚…………………………");
}
}
(5)ProxyFactory.java
package com.Etui.dynamicProxy;
import com.Etui.dynamicProxy.aop.AopService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory implements InvocationHandler {
private Object target; // 代理的目标对
private AopService aop; // 事务切面
public ProxyFactory(Object target, AopService aop) {
this.target = target;
this.aop = aop;
}
// 创建代理对象
public Object createProxy() {
// 创建代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
// System.out.println("所有事务开启前…………………………");
Object result = null; // 执行目标对象的方法
try {
aop.before();
result = method.invoke(target, args);
aop.after();
} catch (Exception e) {
aop.rollback();
}
return result;
}
(6)测试类(MyTest.java)
package com.Etui.test3;
import com.Etui.dynamicProxy.BookServiceImpl;
import com.Etui.dynamicProxy.ProxyFactory;
import com.Etui.dynamicProxy.Service;
import com.Etui.dynamicProxy.aop.AopService;
import com.Etui.dynamicProxy.aop.AopServiceImpl;
import org.junit.Test;
public class MyTest {
// 测试动态代理
@Test
public void testProxy() {
// 创建被代理对象
Service buyBook = new BookServiceImpl();
// 事务切面
AopService aop = new AopServiceImpl();
// 创建代理对象并实现代理
Service bookProxy = (Service) new ProxyFactory(buyBook, aop).createProxy();
// 调用被代理对象的方法
bookProxy.buy();
System.out.println("--------------+++++++--------------");
String result = bookProxy.afterSales(001);
System.out.println("afterSales返回值为:" + result);
}
}