能够理解AOP的作用
能够完成AOP的入门案例
能够理解AOP的工作流程
能够说出AOP的五种通知类型
能够完成"测量业务层接口万次执行效率"案例
能够掌握Spring事务配置
能不能描述一下环绕通知里面的实现步骤?
需求:任意业务层接口执行均可显示其执行效率(执行时长)
分析:
①:业务功能:业务层接口执行前后分别记录时间,求差值得到执行效率 ②:通知类型选择前后均可以增强的类型——环绕通知
xxxxxxxxxx
public class ProjectAdvice {
//匹配业务层的所有方法
"execution(* com.itheima.service.*Service.*(..))") (
private void servicePt(){}
//设置环绕通知,在原始操作的运行前后记录执行时间
"ProjectAdvice.servicePt()") //本类类名可以省略不写 (
public void runSpeed(ProceedingJoinPoint pjp) throws Throwable {
//获取执行的签名对象
Signature signature = pjp.getSignature();
//获取接口/类全限定名
String className = signature.getDeclaringTypeName();
//获取方法名
String methodName = signature.getName();
//记录开始时间
long start = System.currentTimeMillis();
//执行万次操作
for (int i = 0; i < 10000; i++) {
pjp.proceed();
}
//记录结束时间
long end = System.currentTimeMillis();
//打印执行结果
System.out.println("万次执行:"+ className+"."+methodName+"---->" +(end-start) + "ms");
}
}
xxxxxxxxxx
"com.itheima") (
"classpath:jdbc.properties") (
JdbcConfig.class,MybatisConfig.class}) ({
//开启AOP注解功能
public class SpringConfig {
}
xxxxxxxxxx
SpringJUnit4ClassRunner.class) (
classes = SpringConfig.class) (
public class AccountServiceTestCase {
private AccountService accountService;
public void testFindById(){
Account account = accountService.findById(2);
}
public void testFindAll(){
List<Account> list = accountService.findAll();
}
}
在环绕通知中可以获取到哪些数据?
说明:在前置通知和环绕通知中都可以获取到连接点方法的参数们
xxxxxxxxxx
"pt()") (
public void before(JoinPoint jp) {
Object[] args = jp.getArgs(); //获取连接点方法的参数们
System.out.println(Arrays.toString(args));
}
xxxxxxxxxx
"pt()") (
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object[] args = pjp.getArgs(); //获取连接点方法的参数们
System.out.println(Arrays.toString(args));
Object ret = pjp.proceed();
return ret;
}
说明:在返回后通知和环绕通知中都可以获取到连接点方法的返回值
xxxxxxxxxx
value = "pt()",returning = "ret") (
public void afterReturning(String ret) { //变量名要和returning="ret"的属性值一致
System.out.println("afterReturning advice ..."+ret);
}
xxxxxxxxxx
"pt()") (
public Object around(ProceedingJoinPoint pjp) throws Throwable {
// 手动调用连接点方法,返回值就是连接点方法的返回值
Object ret = pjp.proceed();
return ret;
}
说明:在抛出异常后通知和环绕通知中都可以获取到连接点方法中出现的异常
xxxxxxxxxx
value = "pt()",throwing = "t") (
public void afterThrowing(Throwable t) {//变量名要和throwing = "t"的属性值一致
System.out.println("afterThrowing advice ..."+ t);
}
xxxxxxxxxx
"pt()") (
public Object around(ProceedingJoinPoint pjp) {
Object ret = null;
//此处需要try...catch处理,catch中捕获到的异常就是连接点方法中抛出的异常
try {
ret = pjp.proceed();
} catch (Throwable t) {
t.printStackTrace();
}
return ret;
}
请说出我们该使用什么类型的通知来完成这个需求?
需求:对百度网盘分享链接输入密码时尾部多输入的空格做兼容处理
分析: ①:在业务方法执行之前对所有的输入参数进行格式处理——trim() ②:使用处理后的参数调用原始方法——环绕通知中存在对原始方法的调用
xxxxxxxxxx
//-------------service层代码-----------------------
public interface ResourcesService {
public boolean openURL(String url ,String password);
}
public class ResourcesServiceImpl implements ResourcesService {
private ResourcesDao resourcesDao;
public boolean openURL(String url, String password) {
return resourcesDao.readResources(url,password);
}
}
//-------------dao层代码-----------------------
public interface ResourcesDao {
boolean readResources(String url, String password);
}
public class ResourcesDaoImpl implements ResourcesDao {
public boolean readResources(String url, String password) {
System.out.println(password.length());
//模拟校验
return password.equals("root");
}
}
xxxxxxxxxx
public class DataAdvice {
"execution(boolean com.itheima.service.*Service.*(*,*))") (
private void servicePt(){}
"DataAdvice.servicePt()") (
public Object trimStr(ProceedingJoinPoint pjp) throws Throwable {
Object[] args = pjp.getArgs();
for (int i = 0; i < args.length; i++) {
//判断参数是不是字符串
if(args[i].getClass().equals(String.class)){
args[i] = args[i].toString().trim();
}
}
Object ret = pjp.proceed(args);
return ret;
}
}
xxxxxxxxxx
"com.itheima") (
public class SpringConfig {
}
xxxxxxxxxx
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
ResourcesService resourcesService = ctx.getBean(ResourcesService.class);
boolean flag = resourcesService.openURL("http://pan.baidu.com/haha", "root ");
System.out.println(flag);
}
}
概念:AOP(Aspect Oriented Programming)面向切面编程,一种编程范式
作用:在不惊动原始设计的基础上为方法进行功能增强
核心概念
切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)
切入点表达式描述通配符:
切入点表达式书写技巧
1.按标准规范开发 2.查询操作的返回值建议使用*匹配 3.减少使用..的形式描述包 4.对接口进行描述,使用*表示模块名,例如UserService的匹配描述为*Service 5.方法名书写保留动词,例如get,使用*表示名词,例如getById匹配描述为getBy* 6.参数根据实际情况灵活调整
前置通知
后置通知
返回后通知
抛出异常后通知