Spring4框架----aop编程思想(03)
2017-10-30 08:57
190 查看
一、Spring的AOP编程
1、概念:AOP表示的是面向切面编程
好处:在不修改源代码的情况下,可以实现功能的增强2、AOP的实现原理
jdk的动态代理(掌握)注意:jdk动态代理只能对实现了接口的类产生代理
/**
* Jdk的动态代理
* @author kevin
*/
public class JdkProxy
implements InvocationHandler{
//要代理的对象
private CustomerDao
customerDao;
public JdkProxy(CustomerDao
customerDao){
this.customerDao =
customerDao;
}
/**
* 生成代理对象的方法
* @return
*/
public CustomerDao createProxy(){
CustomerDao
proxy = (CustomerDao) Proxy.newProxyInstance(customerDao.getClass().getClassLoader(),
customerDao.getClass().getInterfaces(),
this);
return proxy;
}
/**
* 增强的方法
*/
@Override
public Object invoke(Object
proxy, Method
method, Object[]
args)
throws Throwable {
System.out.println("权限校验...");
return method.invoke(customerDao,
args);
}
}
编写代码测试:
@Test
public void test1(){
CustomerDao
customerDao =
new CustomerDaoImpl();
JdkProxy
jdkProxy =
new JdkProxy(customerDao);
CustomerDao
proxy = jdkProxy.createProxy();
proxy.save();
3、 Cglib动态代理(欣赏)
注意:Cglib可以对没有实现接口的类产生代理,生成子类来实现功能的增强public class CglibProxy
implements MethodInterceptor{
//要代理的对象
private LinkManDao
linkManDao;
public CglibProxy(LinkManDao
linkManDao) {
this.linkManDao =
linkManDao;
}
public LinkManDao createProxy(){
//创建Cglib核心类
Enhancer
enhancer =
new Enhancer();
//设置父类
enhancer.setSuperclass(linkManDao.getClass());
//设置回调
enhancer.setCallback(this);
//生成代理
LinkManDao
proxy = (LinkManDao)
enhancer.create();
return proxy;
}
@Override
public Object intercept(Object
proxy, Method
method, Object[]
args, MethodProxy
methodProxy)
throws Throwable {
System.out.println("日志记录");
Object
obj = methodProxy.invokeSuper(proxy,
args);
return obj;
}
}
编写测试代码
@Test
public void test2(){
LinkManDao
linkManDao =
new LinkManDao();
CglibProxy
cglibProxy =
new CglibProxy(linkManDao);
LinkManDao
proxy = cglibProxy.createProxy();
proxy.save();
}
二、Spring 的AOP开发方式(xml)方式
1、Spring的AOP相关术语的介绍
public class UserDaoImpl{public void save(){}
public void delete(){}
public void list(){}
public void update(){}
}
Target:目标我们需要UserDaoImpl来增强,该类就可以称作为Target
JoinPoint:连接点,在实际开发中可以被增强的点
PointCut:切入点在实际开发中真正被增强的点就称作为PointCut
Advice:通知,我们需要在save()方法中加一个日志记录功能,我们就需要写一个入职记录的方法,那么该方法就是一个通知(增强)
WeAVing:织入,把通知加入到连接点的过程叫做织入
Proxy:代理,增强之后的对象就叫做代理
Introduction:引介,指的是类层面的增强,不需要进行掌握
Aspect:切面,多个advice和PointCut的组合
2、导入AOP开发所需要的jar包
(1) AOP联盟的jar包:com.springsource.org.aopalliance-1.0.0.jar(2)Spring提供的AOP的jar包:spring-aop-4.2.4.RELEASE.jar
(3)AspectJ的jar包:com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
(4)Spring整合AspectJ的jar包:spring-aspects-4.2.4.RELEASE.jar
实例演示;
2.1 编写接口和实现类
ProductDao接口:
public interface ProductDao {
/**
* 持久层:产品保存
*/
public void save();
}
ProductDaoImpl实现类:
public class ProductDaoImpl
implements ProductDao {
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
}
2.2 配置相关类Spring容器中(也就是把相关类交给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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="productDao" class="cn.itcast.dao.impl.ProductDaoImpl"></bean>
</beans>
2.3 编写切面类
/*** 自定义切面类
* @author kevin
*/
public class MyAspectXml {
public void checkPrivilege(){
System.out.println("权限校验...");
}
}
2.4 配置切面类
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="productDao" class="cn.itcast.dao.impl.ProductDaoImpl"></bean>
<bean id="myAspectXml" class="cn.itcast.aspect.MyAspectXml"></bean>
</beans>
2.5 进行AOP配置
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/X
18dec
MLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="productDao" class="cn.itcast.dao.impl.ProductDaoImpl"></bean>
<bean id="myAspectXml" class="cn.itcast.aspect.MyAspectXml"></bean>
<!-- AOP配置 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(*
cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
</beans>
2.6 编写测试类
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")
public class TestAOP {
@Autowired
private ProductDao productDao;
@Test
public void test1(){
productDao.save();
}
}
这个时候发现切面类已经被增强了,也就是在原来的基础上对切面进行增强实现
2.7 切入点表达式的语法
语法:[修饰符]
返回类型 包名.类名.方法名(形式参数)
execution(public * *(..)) 所有的public方法
execution(* set(..)) 所有set开头的方法
execution(* com.xyz.service.AccountService.*(..)) AccountService类中的所有方法
execution(* com.xyz.service.*.*(..))
com.xyz.service包下所有的方法
execution(* com.xyz.service..*.*(..)) com.xyz.service包及其子包下所有的方法
2.8 Spring中的AOP通知类型
2.8.1 前置通知:在方法执行之前增强,可以获得切入点信息
<!-- AOP配置 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(*
cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<!-- 前置通知 -->
<aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
测试:
public class MyAspectXml {
public void checkPrivilege(JoinPoint
point){
System.out.println("权限校验..." +
point);
}
}
2.8.2 后置通知 在方法执行完之后增强。可以获取返回值信息。
<!-- AOP配置 --><aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<!-- 前置通知 -->
<aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
<!-- 后置通知 -->
<aop:after-returning method="afterReturn" pointcut-ref="pointcut2"
returning="result"/>
</aop:aspect>
</aop:config>
测试:
/**
* 自定义切面类
* @author kevin
*/
public class MyAspectXml {
public void checkPrivilege(JoinPoint
point){
System.out.println("权限校验..." +
point);
}
public void afterReturn(Object
result){
System.out.println("后置通知:" +
result);
}
}
public class ProductDaoImpl
implements ProductDao {
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
public int delete(){
System.out.println("持久层:产品删除...");
return 100;
}
}
2.8.3 环绕通知:在方法执行前后都进行增强。可以阻止方法的执行。
<!-- AOP配置 --><aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.update(..))" id="pointcut3"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<!-- 前置通知 -->
<aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
<!-- 后置通知 -->
<aop:after-returning method="afterReturn" pointcut-ref="pointcut2" returning="result"/>
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pointcut3"/>
</aop:aspect>
</aop:config>
测试:
public class ProductDaoImpl
implements ProductDao {
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
public int delete(){
System.out.println("持久层:产品删除...");
return 100;
}
@Override
public void update() {
System.out.println("持久层:产品更新");
}
}
public class MyAspectXml {
public void checkPrivilege(JoinPoint
point){
System.out.println("权限校验..." +
point);
}
public void afterReturn(Object
result){
System.out.println("后置通知:" +
result);
}
public Object around(ProceedingJoinPoint
joinpoint){
System.out.println("环绕前执行");
Object
obj = null;
try {
obj = joinpoint.proceed();
} catch (Throwable
e) {
e.printStackTrace();
}
System.out.println("环绕后执行");
return obj;
}
}
2.8.4 异常抛出通知:当发生异常之后增强,可以获取异常信息。
<!-- AOP配置 --><aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.update(..))" id="pointcut3"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))" id="pointcut4"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<!-- 前置通知 -->
<aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
<!-- 后置通知 -->
<aop:after-returning method="afterReturn" pointcut-ref="pointcut2" returning="result"/>
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pointcut3"/>
<!-- 抛出异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
</aop:aspect>
</aop:config>
测试:
public class ProductDaoImpl
implements ProductDao {
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
public int delete(){
System.out.println("持久层:产品删除...");
return 100;
}
@Override
public void update() {
System.out.println("持久层:产品更新");
}
@Override
public void find() {
System.out.println("持久层:查询");
int i = 10/0;
}
}
public class MyAspectXml {
public void checkPrivilege(JoinPoint
point){
System.out.println("权限校验..." +
point);
}
public void afterReturn(Object
result){
System.out.println("后置通知:" +
result);
}
public Object around(ProceedingJoinPoint
joinpoint){
System.out.println("环绕前执行");
Object
obj = null;
try {
obj =
joinpoint.proceed();
} catch (Throwable
e) {
e.printStackTrace();
}
System.out.println("环绕后执行");
return obj;
}
public void afterThrowing(Exception
ex){
System.out.println("抛出异常通知:" +
ex.getMessage());
}
}
2.8.5 最终通知:不管是否有异常,都会执行
配置:
<!-- AOP配置 --><aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(*
cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
<aop:pointcut expression="execution(*
cn.itcast.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
<aop:pointcut expression="execution(*
cn.itcast.dao.impl.ProductDaoImpl.update(..))" id="pointcut3"/>
<aop:pointcut expression="execution(*
cn.itcast.dao.impl.ProductDaoImpl.find(..))" id="pointcut4"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<!-- 前置通知 -->
<aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
<!-- 后置通知 -->
<aop:after-returning method="afterReturn" pointcut-ref="pointcut2" returning="result"/>
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pointcut3"/>
<!-- 抛出异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
<!-- 最终通知 -->
<aop:after method="after"
pointcut-ref="pointcut4"/>
</aop:aspect>
</aop:config>
测试代码:
public class MyAspectXml {
public void checkPrivilege(JoinPoint
point){
System.out.println("权限校验..." +
point);
}
public void afterReturn(Object
result){
System.out.println("后置通知:" +
result);
}
public Object around(ProceedingJoinPoint
joinpoint){
System.out.println("环绕前执行");
Object
obj = null;
try {
obj =
joinpoint.proceed();
} catch (Throwable
e) {
e.printStackTrace();
}
System.out.println("环绕后执行");
return obj;
}
public void afterThrowing(Exception
ex){
System.out.println("抛出异常通知:" +
ex.getMessage());
}
public void after(){
System.out.println("最终通知");
}
}
最终通知和后置通知的区别:最终通知,不管异常与否,都执行。而后置通知在异常的时候不执行
三、Spring注解形式的AOP入门
第一步、创建工程引入jar包,创建核心配置文件3.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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="cn.itcast"></context:component-scan>
<!-- 开启自动代理注解 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
3.2 创建接口和实现类
public interface ProductDao {/**
* 持久层:产品保存
*/
public void save();
public int delete();
public void update();
public void find();
}
@Repository("productDao")
public class ProductDaoImpl
implements ProductDao {
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
public int delete(){
System.out.println("持久层:产品删除...");
return 100;
}
@Override
public void update() {
System.out.println("持久层:产品更新");
}
@Override
public void find() {
System.out.println("持久层:查询");
}
}
3.3 面向切面编程 编写切面类
@Component("myAspectAnnotation")@Aspect
public class MyAspect {
//前置方法
@Before("execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))")
public void checkPrivilege(JoinPoint
joinPoint){
System.out.println("权限校验..." +
joinPoint.toString());
}
}
提示:此处的切面类可以不取id.
四、Spring的AOP注解通知
4.1 前置通知、
/*** 前置通知
* @param joinPoint
*/
@Before("execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))")
public void checkPrivilege(JoinPoint
joinPoint){
System.out.println("权限校验..." +
joinPoint.toString());
}
4.2. 后置通知
@Aspectpublic class MyAspect {
/**
* 前置通知
* @param joinPoint
*/
@Before("execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))")
public void checkPrivilege(JoinPoint
joinPoint){
System.out.println("权限校验..." +
joinPoint.toString());
}
@AfterReturning(value="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))",returning="result")
public void afterReturning(Object
result){
System.out.println("后置通知:" +
result);
}
}
4.3. 环绕通知
@Around("execution(* cn.itcast.dao.impl.ProductDaoImpl.update(..))")public Object after(ProceedingJoinPoint
joinpoint)
throws Throwable{
System.out.println("环绕通知前增强");
Object
obj = joinpoint.proceed();
System.out.println("环绕通知后增强");
return obj;
}
4.4. 异常通知
@AfterThrowing(value="execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))",throwing="ex")public void afterThrowing(Exception
ex){
System.out.println("抛出异常通知");
}
4.5. 最终通知
@After("execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))")public void after(){
System.out.println("最终通知");
}
4.6. PointCut注解(了解)
作用:用于定义切入点表达式的一个注解。@Component("myAspectAnnotation")
@Aspect
public class MyAspect {
/**
* 前置通知
* @param joinPoint
*/
@Before("execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))")
public void checkPrivilege(JoinPoint
joinPoint){
System.out.println("权限校验..." +
joinPoint.toString());
}
@AfterReturning(value="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))",returning="result")
public void afterReturning(Object
result){
System.out.println("后置通知:" +
result);
}
@Around("execution(* cn.itcast.dao.impl.ProductDaoImpl.update(..))")
public Object aroung(ProceedingJoinPoint
joinpoint)
throws Throwable{
System.out.println("环绕通知前增强");
Object
obj = joinpoint.proceed();
System.out.println("环绕通知后增强");
return obj;
}
//@AfterThrowing(value="execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))",throwing="ex")
@AfterThrowing(value="MyAspect.pointcut()",throwing="ex")
public void afterThrowing(Exception
ex){
System.out.println("抛出异常通知");
}
//@After("execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))")
@After("MyAspect.pointcut()")
public void after(){
System.out.println("最终通知");
}
@Pointcut("execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))")
public void pointcut(){
}
}
相关文章推荐
- Aop_面向切面编程_思想理解资料03 . .
- aop(面向切面)编程思想在spring框架下实现的配置方法
- AngularJS入门知识之MVW类框架的编程思想探讨
- AOP,OOP两种编程思想联系
- 编程思想的理解(POP,OOP,SOA,AOP)
- 框架编程思想
- 编程思想的理解(POP,OOP,SOA,AOP)
- 编程思想的理解(POP,OOP,SOA,AOP)
- 编程思想POP,OOP,SOA,AOP?
- AOP面向切面编程思想的原理(简单理解)
- struts2_day04_01_拦截器概述_02_拦截器底层原理(aop思想)_03_拦截器底层原理(责任链模式)
- 从壹开始前后端分离【 .NET Core2.0 Api + Vue 2.0 + AOP + 分布式】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存
- 深入理解Aop编程思想
- spring4与AOP编程:入门
- Aop_面向切面编程_思想理解资料02 .
- 什么是SpringAop? 面向切面编程-----思想
- 编程思想的理解(POP,OOP,SOA,AOP)
- 基于配置的ORMapping框架浅析之4(面向方面的AOP切面思想引入)
- Web框架梳理:第四章:Spring学习入门、Spring属性注入、AOP编程、注解开发
- Java 编程思想(第4版)学习笔记(各种容器(集合框架)的比较 Collection Map ..第11章 练习4)