1.1 目的
通过静态代理模拟spring中aop,使用静态代理拆分业务和业务接口,切面和切面接口,降低耦合,从而达到灵活拓展业务,为理解动态代理aop做铺垫。
1.2 实现分析
1.2.1 概图分析
spring 采用的是面向接口编程,原因是更加灵活,方法中参数为接口类型,那么只需要传入该接口的实现类,可以更好的去拓展业务。
1.2.2 静态代理是什么?
Java中的静态代理要求代理类(ProxySubject)和委托类(RealSubject)都实现同一个接口(Subject)。静态代理中代理类在编译期就已经确定,而动态代理则是JVM运行时动态生成,静态代理的效率相对动态代理来说相对高一些,但是静态代理代码冗余大,一单需要修改接口,代理类和委托类都需要修改。
购买业务接口:图书购买和商品购买类实现该接口。
切面AOP接口:事务和日志类实现该接口。
代理对象Agent :代理的是购买业务。
委托类:BookServiceImpl 、ProductServiceImpl
代理类 : Agent
2.1 实现过程
Service接口
package cn.itxiaoli;
/**
* @author itxiaoli
* @className Service
* @description:
* @date 2022/4/10 21:01
*/
public interface Service {
void buy();
}
BookServiceImpl 实现类
package cn.itxiaoli;
/**
* @author itxiaoli
* @className BookServiceImpl
* @description:
* @date 2022/4/10 21:01
*/
public class BookServiceImpl implements Service {
@Override
public void buy() {
System.out.println("图书购买");
}
}
ProductServiceImpl 实现类
package cn.itxiaoli;
/**
* @author itxiaoli
* @className ProductServiceImple
* @description:
* @date 2022/4/10 21:01
*/
public class ProductServiceImpl implements Service {
@Override
public void buy() {
System.out.println("商品购买");
}
}
Aop 切面接口
package cn.itxiaoli;
/**
* @author itxiaoli
* @className Aop
* @description:
* @date 2022/4/10 21:02
*/
public interface Aop {
default void before() {
}
default void after() {
}
default void exception() {
}
}
Aop 接口中用 default 关键字来修饰,作用是默认空实现,实现类实现该接口时,不需要强制全部重写,根据需求来指定对应方法的重写,如LogAop日志接口,只重写了before(),其他方法空实现了。
LogAop 实现类
package cn.itxiaoli;
/**
* @author itxiaoli
* @className RizhiAop
* @description:
* @date 2022/4/10 21:17
*/
public class LogAop implements Aop {
@Override
public void before() {
System.out.println("日志执行....");
}
}
TransactionAop 实现类
package cn.itxiaoli;
/**
* @author itxiaoli
* @className ShiwuAop
* @description:
* @date 2022/4/10 21:18
*/
public class TransactionAop implements Aop {
@Override
public void before() {
System.out.println("事务开启");
}
@Override
public void after() {
System.out.println("事务提交");
}
@Override
public void exception() {
System.out.println("事务回滚");
}
}
代理类
package cn.itxiaoli;
/**
* @author itxiaoli
* @className Agent
* @description:
* @date 2022/4/10 21:07
*/
public class Agent implements Service {
private Service target;
private Aop aop;
public Agent(Service target, Aop aop) {
this.target = target;
this.aop = aop;
}
@Override
public void buy() {
try {
// 切面
aop.before();
// 执行业务逻辑
target.buy();
// 切面
aop.after();
} catch (Exception e) {
// 切面
aop.exception();
e.printStackTrace();
}
}
}
测试类
package cn.itxiaoli;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class AppTest {
/**
* Rigorous Test :-)
*/
@Test
public void TestAop() {
Agent agent = new Agent(new BookServiceImpl(), new LogAop());
agent.buy();
System.out.println("==========agent2=======");
Agent agent2 = new Agent(new ProductServiceImpl(), new TransactionAop());
agent2.buy();
System.out.println("=========agent3========");
Agent agent3 = new Agent(agent2, new LogAop());
agent3.buy();
}
}
控制台agent3中在事务切面开启时,首先执行了日志切面,达到了嵌套事务,增强业务功能。原因是Agent类也实现了购买接口中的buy()方法,所以new Agent()中的第一个参数为实现购买接口的实现类对象,是多态的体现。