JavaEE——Spring学习笔记03【AOP开发】
JavaEE——Spring学习笔记01【Ioc开发的模式】
JavaEE——Spring学习笔记02【Spring和Mybatis的整合】
JavaEE——Spring学习笔记03【AOP开发】
JavaEE——Spring学习笔记04【Spring的事务管理】
JavaEE——Spring学习笔记05【Mybatis的逆行工程】
JavaEE——Spring学习笔记06【Maven创建Web工程】
目录
六、Spring的AOP开发
1. AOP的概念
2. 动态代理(了解)
2.1 JDK动态代理
2.2 Cglib动态代理
3. AOP的编程的好处
4. AOP的编程相关术语
5. AOP的开发模式
5.1 Aop的Xml开发方式
5.2 Aop的注解开发方式
六、Spring的AOP开发
1. AOP的概念
AOP的英文全程为Aspect Oriented programming,叫做面向切面编程,主要是在运行期间动态实现在不修改源码的情况下给程序及进行功能增强。针对目标功能进行扩展或是增强,通俗来说就是不修改源码,让目标获得它本身没有用的新功能。其实就是OOP编程的一个补充,降低了代码的耦合性。
AOP开发的底层是通过动态代理来完成,动态代理分为JDK动态代理和Cglib动态代理。
JDK动态代理:依赖于一个接口
Cglib动态代理:依赖一个类
2. 动态代理(了解)
2.1 JDK动态代理
只能对实现了接口的类产生代理。
实现的步骤:
1)业务的接口和实现类
/** 用户的接口* */
public interface UserDao {public void save();public void update();public void find();public void delete();
}
/** 用户接口实现类* */
public class UserDaoImpl implements UserDao {@Overridepublic void save() {System.out.println("保存用户信息");}@Overridepublic void update() {System.out.println("更改用户信息");}@Overridepublic void find() {System.out.println("查询用户信息");}@Overridepublic void delete() {System.out.println("删除用户信息");}
}
2)JDK动态代理的类
/** JDK动态代理的类:实现Invocation Handler* */
public class JdkProxy implements InvocationHandler {//将被增强的对象传递进来(目标类)private UserDao userDao;public JdkProxy(UserDao userDao) {this.userDao = userDao;}//产生UserDao代理的方法public UserDao createProxy() {/** 第一个参数:UserDao类的加载器* 第二个参数:要实现的接口* */UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(), this);return userDaoProxy;}/* 方法功能增强* 第一个参数: 代理对象* 第二个参数: 真正执行的方法* 第三个参数: 是方法的参数* */@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if ("save".equals(method.getName())) {//增强System.out.println("权限校验==========");return method.invoke(userDao, args);}return method.invoke(userDao, args);}
}
3)测试方法
/** 用户方法增强的测试类* */
public class UserDaoTest {public static void main(String[] args) {//创建一个UserDao的实现类对象UserDao userDao = new UserDaoImpl();//创建代理的对象UserDao proxy = new JdkProxy(userDao).createProxy();proxy.save();proxy.update();proxy.find();proxy.delete();}
}
2.2 Cglib动态代理
1)针对类而言:引入第三代理的jar包
<!--添加Cglib动态代理的jar包--><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.1_3</version></dependency>
2)目标类
/** 客户信息的类* */
public class CustomerService {public void save() {System.out.println("保存用户信息");}public void update() {System.out.println("更改用户信息");}public void find() {System.out.println("查询用户信息");}public void delete() {System.out.println("删除用户信息");}
}
3)Cglib代理的类
/** CglibProxy动态代理的类:实现MethodInterceptor* */
public class CglibProxy implements MethodInterceptor {//给出要代理的对象private CustomerService customerService;public CglibProxy(CustomerService customerService) {this.customerService = customerService;}/** 使用Cglib产生代理的方法* */public CustomerService createProxy() {//1.创建Cglib的核心类的对象Enhancer enhancer = new Enhancer();//2.设置父类enhancer.setSuperclass(customerService.getClass());//3.设置回滚enhancer.setCallback(this);//4.创建代理的对象CustomerService proxy = (CustomerService) enhancer.create();return proxy;}/** 功能增强* */@Overridepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//判断方法if ("delete".equals(method.getName())) {//增强System.out.println("日志信息==========");return methodProxy.invokeSuper(proxy, args);}return methodProxy.invokeSuper(proxy, args);}
}
4)测试的类
/** 客户信息测试类* */
public class CustomerServiceTest {public static void main(String[] args) {//创建一个目标类CustomerService customerService = new CustomerService();//代理过程CustomerService proxy = new CglibProxy(customerService).createProxy();proxy.save();proxy.update();proxy.find();proxy.delete();}
}
3. AOP的编程的好处
1.减少重复
2.专注于业务功能增强的实现,就是oop的补充。
3.解模块之间的耦合性
4.实现了事务的功能管理
5.。。。。。
4. AOP的编程相关术语
1)切面:Aspect
切面指的是一个辅助类,实际上就是对业务逻辑的一种增强管理类。
2)连接点:JointPoint
连接点是指可以被切面植入的具体的方法,通常情况就是业务中的方法均可以作为连接点。
3)切入点:PointCut
切入点(切点)声明一个或多个连接点的集合,一般我们理解为真正被增强的那个方法或方法的集合。
4)目标对象:Target
目标对象就是指被增强的对象,即包含业务逻辑的类的对象
5)通知:Advice
通知定义了增强代码切入到目标代码的时间点(可前可后进行增强),是目标方法执行前还是执行后等,通知的类型不同,导致切入的时间点就不一样了。
6)织入:weaving
织入就是增强添加对目标类具体连接点的过程。
5. AOP的开发模式
5.1 Aop的Xml开发方式
Spring本身有自己对AOP开发的实现,但是开发者发现了这个过程太过于繁琐了,所以在实际开发中我们使用的是AspectJ技术实现对AOP的开发,其实就是简化Spring本身的开发。其实现方式简洁、方便管理,而且还支持注解开发。所以Spring又将AspectJ作为AOP实现引入到自己框架中。
log4j.properties日志配置 log4j.rootLogger = debug,stdout,D,Elog4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%nlog4j.appender.D = org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File = D://logs/log.log log4j.appender.D.Append = true log4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%nlog4j.appender.E = org.apache.log4j.DailyRollingFileAppender log4j.appender.E.File =D://logs/error.log log4j.appender.E.Append = true log4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
5.1.1 前置通知:berfore
1)引入AspectJ的依赖jar包
<dependencies><!--添加单元测试的依赖包--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><!--添加Spring的核心jar包--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.7.RELEASE</version></dependency><!--添加AspectJ的依赖包--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.7.RELEASE</version></dependency></dependencies>
2)配置切面(就是业务增强的那个类)AccountAspect
/** 账户类的切面:其实就是Account业务增强的类* */
public class AccountAspect {/** 验证账户的合法性* */public void validAuth() {System.out.println("验证账户是否合法!");}/** 检查余额是否足够* */public void validMoney() {System.out.println("检查余额是否充足!");}/** 生成对账单* */public void generateStatement() {System.out.println("生产对账单!");}/** 发送短信* */public void sendMsg() {System.out.println("发送短信!");}/** 后置通知:取完钱后查看余额的方法* */public void getYuMoney(Object result) {System.out.println("账户余额还有:" + result);}/** 利用环绕通知检查余额是否足够(前置)和生成对账单(后置)* */public Object validMoneyAndGenerateStatement(ProceedingJoinPoint point) throws Throwable {Object obj = null;//前置通知: 检查余额是否充足validMoney();obj = point.proceed(); //调用切点的方法//后置通知: 生成对账单generateStatement();return obj;}/** 异常通知* */public void exception(Exception e) {System.out.println("目标方法执行出错" + e.getMessage());}/** 最终的通知* */public void after() {System.out.println("不管有无异常,我都进行通知");}
}
3) 配置被切面(就是配置目标类)Account
/** 账号类* */
public class Account {int money = 1000;//取钱/*public void out() {money -= 100; //取出100元System.out.println("已扣除100元!");}*///取钱public int out() {money -= 100; //取出100元System.out.println("已扣除100元!");int num = 100 / 0; //设置异常return money;}//存钱public void in() {money += 100; //存储100元System.out.println("已存储100元!");}//转账public void transfer() {System.out.println("转账人民币!");}//开户public void open() {System.out.println("开通账户!");}//销户public void close() {System.out.println("销毁账户!");}
}
4)配值目标类和切面类的关系applicationContext-aop.xml
Spring容器管理
<?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"><!--1.配置切面: 业务增强的类--><bean id="accountAspect" class="com.suke.aspect.AccountAspect"></bean><!--2.配置被切面: 目标类--><bean id="account" class="com.suke.pojo.Account"></bean><!--3.配置切面和目标类之间的关系--><aop:config><!--3.1 配置切入点:真正被增强的那个点(方法)--><aop:pointcut id="pointcut1" expression="execution(public int com.suke.pojo.Account.out())"/><!--3.2 配置切面,给出增强的方法的执行时间通知的配置:方法被增强的执行时间:之前,之后,环绕,异常,最终--><aop:aspect ref="accountAspect"><!--配置增强的方法--><!--前置通知--><aop:before method="validAuth" pointcut-ref="pointcut1"/><aop:before method="validMoney" pointcut-ref="pointcut1"/><!--后置通知,给出余额参数信息--><aop:after-returning method="getYuMoney" pointcut-ref="ponintcut1" returning="result"/><!--环绕通知--><aop:around method="validMoneyAndGenerateStatement" pointcut-ref="pointcut1"/><!--异常通知--><aop:after-throwing method="exception" pointcut-ref="pointcut1" throwing="e"/><!--最终异常--><aop:after method="after" pointcut-ref="pointcut1"/></aop:aspect></aop:config>
</beans>
5)测试类AccountTest
/** 测试账户的类* */
public class AccountTest {@Testpublic void testAccount() {//1.创建Spring容器的对象ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-aop.xml");//2.获取容器中Account对象Account account = (Account) applicationContext.getBean("account");//取钱account.out();}
}
5.1.2 后置通知:after-returing
在目标方法执行后进行通知
1)以取钱后显示余额为案例,目标类中的方法
//取钱public int out() {money -= 100; //取出100元System.out.println("已扣除100元!");return money;}
2)切面类中的方法
/** 后置通知:取完钱后查看余额的方法* */public void getYuMoney(Object result) {System.out.println("账户余额还有:" + result);}
3)Spring容器中的配置
<!--后置通知,给出余额参数信息--><aop:after-returning method="getYuMoney" pointcut-ref="ponintcut1" returning="result"/>
5.1.3 环绕通知:aroud
在目标方法执行前和执行后都进行通知,修改切面类中的方法!
1)切面类中的方法
/** 利用环绕通知检查余额是否足够(前置)和生成对账单(后置)* */public Object validMoneyAndGenerateStatement(ProceedingJoinPoint point) throws Throwable {Object obj = null;//前置通知: 检查余额是否充足validMoney();obj = point.proceed(); //调用切点的方法//后置通知: 生成对账单generateStatement();return obj;}
2)Spring容器中的配置
<!--环绕通知--><aop:around method="validMoneyAndGenerateStatement" pointcut-ref="pointcut1"/>
3)测试类不变
/** 测试账户的类* */
public class AccountTest {@Testpublic void testAccount() {//1.创建Spring容器的对象ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-aop.xml");//2.获取容器中Account对象Account account = (Account) applicationContext.getBean("account");//取钱account.out();}
}
5.1.4 异常通知:after-throwing
1)目标类中的方法
//取钱public int out() {money -= 100; //取出100元System.out.println("已扣除100元!");int num = 100 / 0; //设置异常return money;}
2)切面类中的方法
/** 异常通知* */public void exception(Exception e) {System.out.println("目标方法执行出错" + e.getMessage());}
3)Spring容器中的配置
<!--异常通知--><aop:after-throwing method="exception" pointcut-ref="pointcut1" throwing="e"/>
4)测试类不变
5.1.5 最终通知:after
1)切面类中的方法
/** 最终的通知* */public void after() {System.out.println("不管有无异常,我都进行通知");}
2)Spring容器文件中的配置
<!--最终异常--><aop:after method="after" pointcut-ref="pointcut1"/>
3)测试类不变
AOP的总结:
1. 切什么?用什么切?
找切面与被切面,被切面是业务,切面是扩展业务
2. 从哪切?
找切点
3. 什么时间切?
定义通知类型(前置,后置,环绕,异常,最终)
5.2 Aop的注解开发方式
无论是xml的aop开发。还是注解的aopo开发,都可以实现方法增强的功能。
5.2.1 设置注解的包扫描器
<?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"xmlns:context="http://www.springframework.org/schema/context"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.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!--1、设置注解的包扫描器--><context:component-scan base-package="com.suke"/><!--2、开启AOP的注解代理--><aop:aspectj-autoproxy/>
</beans>
5.2.2 AOP注解在使用前要先开启
<?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"xmlns:context="http://www.springframework.org/schema/context"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.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!--1、设置注解的包扫描器--><context:component-scan base-package="com.suke"/><!--2、开启AOP的注解代理--><aop:aspectj-autoproxy/>
</beans>
5.2.3 目标类Account
/*** 账户类:被切面类*/@Component
public class Account {int money = 1000;//取钱
/* public void out(){money -=100;//取出100System.out.println("已扣除100元!");}*/public int out() {money -= 100;//取出100System.out.println("已扣除100元!");//int num = 100/0;//设置异常return money;}//存钱public void in() {money += 100;//存储100System.out.println("已存储100元!");}//转账public void transfer() {System.out.println("转账人民币!");}//开户public void open() {System.out.println("开通账户!");}//销户public void close() {System.out.println("账户销户!");}
}
5.2.4 切面类AccountAspect
/*** 账户类的切面:其实就是Account业务增强的类*/
@Component
@Aspect
public class AccountAspect {/*** 验证账户的合法性:前置通知1*/@Before("execution(public int com.suke.pojo.Account.out())")public void validAuth() {System.out.println("验证账户是否合法!");}/*** 检查余额是否足够:前置通知2*/@Before("execution(public int com.suke.pojo.Account.out())")public void validMoney() {System.out.println("检查余额是否充足!");}/*** 生成对账单*/@AfterReturning("execution(public int com.suke.pojo.Account.out())")public void generateStatement() {System.out.println("生成对账单!");}/*** 发送短信*/@AfterReturning("execution(public int com.suke.pojo.Account.out())")public void sendMsg() {System.out.println("发送短信!");}/*** 后置通知:取完钱后查看余额的方法*/
// @AfterReturning(value = "execution(public int com.suke.pojo.Account.out())",returning = "result")@AfterReturning(value = "accountPoint()", returning = "result")public void getYuMoney(Object result) {System.out.println("账户余额还有:" + result);}/*** 利用环绕通知检查余额是否足够(前置)和生成对账单(后置)*/@Around("execution(public int com.suke.pojo.Account.out())")public Object vaildMoneyAndGenerateStatement(ProceedingJoinPoint ponint) throws Throwable {Object obj = null;//前置通知:检查余额是否充足validMoney();obj = ponint.proceed(); //调用切点的方法//后置通知:生成对账单generateStatement();return obj;}/*** 异常通知*/
// @AfterThrowing(value = "execution(public int com.suke.pojo.Account.out())", throwing = "e")@AfterThrowing(value = "accountPoint()", throwing = "e")public void exception(Exception e) {System.out.println("目标方法执行出错!" + e.getMessage());}/*** 最终的通知*/
// @After("execution(public int com.suke.pojo.Account.out())")@After(value = "accountPoint()")public void after() {System.out.println("不管有无异常我都进行通知!");}/*** 配置一个切点*/@Pointcut(value = "execution(public int com.suke.pojo.Account.out())")public void accountPoint() {}
}
5.2.4 测试类AccountTest
/*** 测试账户的类*/
public class AccountTest {@Testpublic void testAccount(){//1、创建Spring的容器对象ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-aop.xml");//2、获取容器中Account对象Account account = (Account) applicationContext.getBean("account");//取钱account.out();}
}
JavaEE——Spring学习笔记03【AOP开发】相关推荐
- JavaEE——Spring学习笔记01【Ioc开发的模式】
JavaEE--Spring学习笔记01[Ioc开发的模式] JavaEE--Spring学习笔记02[Spring和Mybatis的整合] JavaEE--Spring学习笔记03[AOP开发] J ...
- Spring 学习笔记----->AOP
Spring 学习笔记----->AOP 代理模式 为什么学代理模式? 因为这就是Spring Aop的底层 代理模式的分类: 静态代理 动态代理 静态代理 生活用的例子: 房东 public ...
- Spring学习笔记002 - AOP
2019独角兽企业重金招聘Python工程师标准>>> 一.AOP的几个概念 1.Aspect,表示切面功能 配置如下: <?xml version="1.0&quo ...
- 【Spring学习笔记】AOP
文章目录 一.何为AOP? 二.AOP相关术语 三.AOP流行框架比较 四.动态代理 1.创建接口UserDao 2.创建实现类 UserDaoImpl 3.创建切面类MyAspect 4.创建代理类 ...
- Spring学习笔记之AOP配置篇(一) 注解配置
目录 1. 创建并声明一个切面 2. 使用切面的通知 3. 定义切面的优先级 4. 使用切入点表达式 1. 创建并声明一个切面 首先,创建一个类,添加@Component注解使其添加到IoC容器 然后 ...
- JDBC学习笔记03【JDBC事务管理、数据库连接池、JDBCTemplate】
黑马程序员-JDBC文档(腾讯微云)JDBC笔记.pdf:https://share.weiyun.com/Kxy7LmRm JDBC学习笔记01[JDBC快速入门.JDBC各个类详解.JDBC之CR ...
- 【Spring学习笔记 九】Spring声明式事务管理实现机制
什么是事务?事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用,关乎数据准确性的地方我们一定要用到事务,防止业务逻辑出错. 什么是事务管理,事务管理对于企业应用而言至 ...
- 一箭双雕 刷完阿里P8架构师spring学习笔记+源码剖析,涨薪8K
关于Spring的叙述: 我之前死磕spring的时候,刷各种资料看的我是一头雾水的,后面从阿里的P8架构师那里拿到这两份资料,从源码到案例详细的讲述了spring的各个细节,是我学Spring的启蒙 ...
- spring学习笔记(一)创建对象的四种方式
spring学习笔记(一)创建对象的四种方式 一.简介 Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架. 所谓IoC就是Iversion of Control,控制反 ...
最新文章
- SpringBoot使用Socket向前端推送消息
- 【项目】MD5加盐源码理解
- [NOIP2006] 提高组 洛谷P1066 2^k进制数
- 初探swift语言的学习笔记三(闭包-匿名函数)
- context 的理解
- PHP之MVC项目实战
- IPC--进程间通信四(信号量)
- 配置oracle odbc驱动,oracle odbc driver configuration
- springboot session超时设置_Spring Boot+Spring Security:获取用户信息和session并发控制...
- 苹果apple id无法申请开发者帐号问题
- 中国黑客VS外国黑客,5分钟让你明白谁更技高一筹
- python 音乐相册_App Store 上的“魔力相册-音乐相册、视频电子相册制作工具”...
- 网上订餐叫外卖的发展优势
- 医疗机构如何成功实施CRM?如下几点是关键因素
- 关于Windows Server 2012 网络发现启动不了
- 最全IDC数据中心知识讲解(一)
- 从零开始自学微信小程序(一)
- linux脚本创建快捷方式,批处理BAT创建快捷方式
- 英勇地死去 VS 卑贱地活着
- tomcat基础简介与示例
热门文章
- 取分组中每组里的第一条/最后一条数据
- python计算n阶乘中尾部零的个数_计算n阶乘中尾部零的个数
- 海思ubootsd卡协议
- MPAndroidChart之PieChart
- Unity3D图片质量设置
- 2021年邯郸一中高考成绩查询,2021年邯郸高考状元名单公布,邯郸文理科状元是谁多少分...
- 数据表的修改、删除与表中记录的录入
- 力扣 790. 多米诺和托米诺平铺
- 为什么调用glPushMatrix()和glPopMatrix()
- Ruoyi实现单文件上传和多文件打包压缩包下载