Spring框架使用Api接口实现AOP的切面编程、两种方式的程序示例以及Java各数据类型及基本数据类型的默认值/最大值/最小值列表
一、Spring框架使用Api接口-继承类实现AOP的切面编程示例
要使用Spring框架AOP,除了要导入spring框架包外,还需要导入一个织入的包org.aspectj,具体maven依赖如下:
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.10.RELEASE</version>
</dependency>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.6.9</version></dependency>
注,本文最先发表于publish:September 29, 2020 -Tuesday,在后来发现此时的代码已经有问题了,依赖的包加载报错,aspectj的版本需要换一下,我这里换成1.9.9后正常。
然后我们编写几个类,一个是接口类ArticleInterface,二是这个接口的实现类Article,三是需要往这个实现类Article中切入的切面类:BeforeLog 和AfterLog 分别在方法执行起和末尾执行的方法。类的实现代码如下:
//接口类ArticleInterface
package proxy;public interface ArticleInterface {public void query(); public void add() ;public void edit() ;public void delete() ;
}//接口的实现类Article
package proxy;public class Article implements ArticleInterface{public void query() {System.out.println("获取了一篇文章"); }public void add() {System.out.println("添加了一篇文章");}public void edit() {System.out.println("修改了一篇文章");}public void delete() {System.out.println("删除了一篇文章");}
}//前置切面类
package proxy;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;public class BeforeLog implements MethodBeforeAdvice{//Method 目标对象的方法;Object:目标对象;target:目标对象public void before(Method method, Object[] args, Object target) throws Throwable {// TODO Auto-generated method stub//此方法内容在目标方法执行前会自动执行System.out.println("开始执行方法:" + target.getClass().getName() + "." + method.getName());}}//后置切面类
package proxy;import java.lang.reflect.Method;import org.springframework.aop.AfterReturningAdvice;public class AfterLog implements AfterReturningAdvice{public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {// TODO Auto-generated method stubSystem.out.println("执行方法完成:" + target.getClass().getName() + "." + method.getName() );}}
注意,前置切面类和后置切面类分别实现了MethodBeforeAdvice和AfterReturningAdvice接口,也正因此他们能切入方法进行执行。至于切入至哪个目标类的哪个方法执行,需要我们进入applicationContext.xml中进行aop配置。如上我们需要将这两个切面类BeforeLog和AfterLog加至Article执行。applicationContext.xml的配置及运行结果如下:
<?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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 上方导入aop约束 --><aop:aspectj-autoproxy /><bean id="article" class="proxy.Article" /><bean id="beforelog" class="proxy.BeforeLog" /><bean id="afterlog" class="proxy.AfterLog" /><!-- 进行aop配置 --><aop:config><!-- 表示:Article.*(..) Article类的所有方法任意参数 --><aop:pointcut expression="execution(* proxy.Article.*(..))" id="logcut"/><aop:advisor advice-ref="beforelog" pointcut-ref="logcut"/><aop:advisor advice-ref="afterlog" pointcut-ref="logcut"/></aop:config></beans>
程序的运行结果如下:
//运行结果如下:
开始执行方法:proxy.Article.add
添加了一篇文章
执行方法完成:proxy.Article.add
二、Spring使用自定义类来实现AOP切面编程
上一篇文章 使用Sprint的API(即要添加的通知功能都实现于Spring的接口)实现了AOP切面编程,也可以使用自定义的类来实现,我们可以写一个独立的CLASS类和一些方法,然后通过在applicationContext IOC容器配置中自定义切面 ,在这个切面中自定义我们的切入点并ref相关的方法从而实现切面编程。同样我们编写一个interface Printers和Computer类,还有一个自定义的横切关注点(切面,即自定义类)。代码如下:
//interface
package aspect;public interface Printers {public void print();
}//interface的实现类
package aspect;public class Computer implements Printers{public void print() {System.out.println("打印机执行打印");}}//自定义的横切关注点类
package aspect;public class PrintReady {public void ready() {System.out.println("准备墨水和纸");}public void clear() {System.out.println("整理桌面");}}
如上,我们编写了一个计算类,其有打印的方法,而我们想在打印机执行打印前后添加点其它功能,比如打印执行前准备墨水和纸,打印后整理桌面。注意看我们的横切关注点类PrintReady没有继承任何的Spring类或者接口。然后我们开始编辑applicationContext.xml配置,以及如下:
<?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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><aop:aspectj-autoproxy /><bean id="computer" class="aspect.Computer" /><bean id="printready" class="aspect.PrintReady" /><aop:config><!-- 自定义切面 --><aop:aspect ref="printready"><!-- 切点 --><aop:pointcut expression="execution(* aspect.Computer.*(..))" id="doprint"/><aop:before method="ready" pointcut-ref="doprint" /><aop:after method="clear" pointcut-ref="doprint"/></aop:aspect></aop:config>
</beans>
测试类User的代码及运行结果如下:
package com.kermit.dotest;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import aspect.Printers;public class User {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");Printers computer = (Printers)context.getBean("computer");computer.print();}
}
运行结果如下:
//运行结果
准备墨水和纸
打印机执行打印
整理桌面
三、后来使用Api接口实现AOP切面编程的补充测试记录
1. execution缺少括号不报错但是切面方法就是不执行的坑
在测试的时候发现有一个坑,aplicationContext.xml配置文件中,如果expression里面少了一个括号,程序执行并不报错,但是就是不会执行AOP切面方法,如下请注意 代码 expression="execution(* com.kermit.aoptest.Article.*(..)"/> 中少了一个右括号,程序不报错,导致排查时一直未发现,还以为是哪里加载出现了问题。
<bean id="beforelog" class="com.kermit.aoptest.BeforeLog" /><bean id="afterlog" class="com.kermit.aoptest.AfterLog" /><aop:config><aop:pointcut id="logcut" expression="execution(* com.kermit.aoptest.Article.*(..)"/><aop:advisor advice-ref="beforelog" pointcut-ref="logcut"/><aop:advisor advice-ref="afterlog" pointcut-ref="logcut" /></aop:config>
2. 使用Spring的API接口实现AOP编程有两种方式
文章1是一种实现方式,其是将要切入的类方法都继承自 Spring的类方法 org.springframework.aop.MethodBeforeAdvice;和org.springframework.aop.AfterReturningAdvice; 还有一种方式是使用自定义类,先自己配置一个类实现方法前和方法后要切入的方法,然后加入切面中。
被切入的类内容如下:
package com.kermit.aoptest;import org.springframework.stereotype.Component;import java.sql.SQLOutput;
@Component
public class Article implements ArticleInterface{@Overridepublic void insert() {System.out.println("insert one record.");}@Overridepublic void update() {System.out.println("update one record.");}
}
自定义要切入的方法内容类定义如下:
package com.kermit.aoptest;public class DiyLog {public void before(){System.out.println("do before method");}public void after(){System.out.println("do after method");}
}
然后在配置文件中使用如下配置:
<bean id="diylog" class="com.kermit.aoptest.DiyLog" /><aop:config><aop:aspect ref="diylog"><aop:pointcut id="logcut" expression="execution(* com.kermit.aoptest.Article.*(..))"/><aop:before method="before" pointcut-ref="logcut"/><aop:after method="after" pointcut-ref="logcut"/></aop:aspect></aop:config>-->
这种方法与第1种方法相比,其的局限性比较大,因为其切入的只能是一些独立的方法内容,功能受限。
四、Java各数据类型的默认值/最大值/最小值
以前保存的 Java获取数据类型及基本数据类型的默认值、最大值、最小值保存在这里。
1. Java取各数据类型的认值/最大值/最小值的程序
//Java获取变量的数据类型及基本数据类型的默认值、最大最小值
package data.type;
public class Array {static boolean bool;static byte by;static char ch;static double dv;static float fv;static int iv;static long lv;static short shv;static String strv;public static void main(String[] args) {//Java中的基本数据类型System.out.println("------------各数据类型定义------------");byte b = 2; showType(b);short s = 3;showType(s);int i =10; showType(i);long l =19; showType(l);float f=1.3f;showType(f);double d=0.5;showType(d);char c ='a';showType(c);boolean bo = true; showType(bo);//Java 基本数据类型的默认值System.out.println("---------各类型默认值-------------");System.out.println("Bool :" + bool);System.out.println("Byte :" + by);System.out.println("Character:" + ch);System.out.println("Double :" + dv);System.out.println("Float :" + fv);System.out.println("Integer :" + iv);System.out.println("Long :" + lv);System.out.println("Short :" + shv);System.out.println("String :" + strv);//Java 基本数据类型的信息System.out.println("---------各类型信息-------------");System.out.println("byte类型字节数:"+ Byte.BYTES + ",最小值:" + Byte.MIN_VALUE + ",最大值"+Byte.MAX_VALUE);System.out.println("short类型字节数:"+ Short.BYTES + ",最小值:" + Short.MIN_VALUE + ",最大值"+Short.MAX_VALUE);System.out.println("int类型字节数:"+ Integer.BYTES + ",最小值:" + Integer.MIN_VALUE + ",最大值"+Integer.MAX_VALUE);System.out.println("long类型字节数:"+ Long.BYTES + ",最小值:" + Long.MIN_VALUE + ",最大值"+Long.MAX_VALUE);System.out.println("float类型字节数:"+ Float.BYTES + ",最小值:" + Float.MIN_VALUE + ",最大值"+Float.MAX_VALUE);System.out.println("double类型字节数:"+ Double.BYTES + ",最小值:" + Double.MIN_VALUE + ",最大值"+Double.MAX_VALUE);System.out.println("char类型字节数:"+ Character.BYTES + ",最小值:" + (int)Character.MIN_VALUE + ",最大值"+ (int)Character.MAX_VALUE);}public static void showType(Object obj) {System.out.println(obj.getClass().getTypeName() );}
}
2. Java取各数据类型的认值/最大值/最小值的程序运行结果:
------------各数据类型定义------------
java.lang.Byte
java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double
java.lang.Character
java.lang.Boolean
---------各类型默认值-------------
Bool :false
Byte :0
Character:
Double :0.0
Float :0.0
Integer :0
Long :0
Short :0
String :null
---------各类型信息-------------
byte类型字节数:1,最小值:-128,最大值127
short类型字节数:2,最小值:-32768,最大值32767
int类型字节数:4,最小值:-2147483648,最大值2147483647
long类型字节数:8,最小值:-9223372036854775808,最大值9223372036854775807
float类型字节数:4,最小值:1.4E-45,最大值3.4028235E38
double类型字节数:8,最小值:4.9E-324,最大值1.7976931348623157E308
char类型字节数:2,最小值:0,最大值65535