公司自研一套服务治理框架,只需实现特定接口便可在服务中心上注册服务,但该框架有一套自动重发机制,在网络抖动状况下可能会重复交易(例如重复放款),并不是全部交易系统都有完善的交易流水控制机制。为了解决重复交易问题,尽量的下降代码侵入性,因此使用aop+aspectj+redis解决这一问题。git
一、maven 项目。github
二、JDK 1.7redis
整体介绍,spring aop分为jdk和cglib两种动态代理,一般咱们使用cglib的方式,cglib会在启动初始化时加载稍慢,在后期运行时效率更高而且能够支持无接口的代理。经过 aop+aspectj方式是我的认为自动化程度最高,开发工做最少的实现方法,可是spring aop的实现方法远不止于此。spring
aop+aspectj,主要任务为编写aspectj拦截类,bean上添加@Aspect注解,bean中能够添加@Around、@Before()、@After()等注解。在spring配置文件中开启aspectj便可,<aop:aspectj-autoproxy proxy-target-class="true"/>,true时使用cglib代码。如下为详细说明。apache
一、服务接口、接口实现、实体对象。编程
package com.aop.api; import com.aop.request.RequestData; import com.aop.response.ResponseData; public interface ApiInterface { ResponseData helloWorld(RequestData requestData); }
package com.aop.service; import com.aop.api.ApiInterface; import com.aop.request.RequestData; import com.aop.response.ResponseData; import org.springframework.stereotype.Service; @Service public class ApiImpl implements ApiInterface { @Override public ResponseData helloWorld(RequestData requestData) { ResponseData responseData = new ResponseData("SUCCESS","请求成功!"); System.out.println("impl 请求参数:" + requestData.getData()); return responseData; } }
package com.aop.request; public class RequestData { private String data; public RequestData(String data) { this.data = data; } public String getData() { return data; } public void setData(String data) { this.data = data; } @Override public String toString() { return "RequestData{" + "data='" + data + '\'' + '}'; } }
package com.aop.response; public class ResponseData { private String respCode; private String respDesc; public ResponseData(String respCode, String respDesc) { this.respCode = respCode; this.respDesc = respDesc; } @Override public String toString() { return "ResponseData{" + "respCode='" + respCode + '\'' + ", respDesc='" + respDesc + '\'' + '}'; } }
二、拦截AOPapi
package com.aop.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Component @Aspect public class AopIntercept { /** * 只有around拦截能够使用joinPoint。咱们就练习这个相对复杂的 * * @param joinPoint * @return */ //execution 拦截点介绍:第一个* 表示全部返回值,第二个*表示全部方法,后面的(..)表示这个方法中全部入参。即拦截ApiInterface下全部方法 @Around("execution(* com.aop.api.ApiInterface.*(..))") public Object around(ProceedingJoinPoint joinPoint) { before(); //得到全部请求参数 Object[] args = joinPoint.getArgs(); for (Object obj : args) { System.out.println("拦截中请求参数:" + obj.toString()); } Object obj = null; try { obj = joinPoint.proceed(); System.out.println("拦截中方法返回值:" + obj.toString()); } catch (Throwable throwable) { throwable.printStackTrace(); } after(); return obj; } private void before() { //流水号重复校验 System.out.println("拦截方法前执行!"); } private void after() { System.out.println("拦截方法后执行!"); } }
三、配置文件、pom文件网络
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd " xmlns:aop="http://www.springframework.org/schema/aop"> <context:component-scan base-package="com.aop"/> <!-- 动态代理默认jdk使用cglib时设置成true--> <aop:aspectj-autoproxy proxy-target-class="true"/> </beans>
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.aop.test</groupId> <artifactId>aop</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.7.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.7.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/aspectj/aspectjweaver --> <dependency> <groupId>aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.5.4</version> </dependency> </dependencies> <build> <finalName>aop</finalName> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/**</include> </includes> <filtering>true</filtering> </resource> </resources> <plugins> <plugin> <artifactId>maven-resources-plugin</artifactId> <!--<version>2.5</version>--> <configuration> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> </project>
四、测试代码。app
package com.aop; import com.aop.api.ApiInterface; import com.aop.request.RequestData; import com.aop.response.ResponseData; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); ApiInterface apiInterface = context.getBean(ApiInterface.class); ResponseData responseData = apiInterface.helloWorld(new RequestData("请求参数:name=张三")); System.out.println("main end response:" + responseData); } }
五、输出结果。框架
咱们经过aop方式,在before()方法中加入redis,经过在redis中检查流水号的key是否已存在来断定是否为重复交易。
下面在介绍一些经常使用的aop方式
一、基于XML配置的Spring AOP。
二、编程式aop等。
https://github.com/binary-vi/binary.github.io/tree/master/aop