Java EE SSH框架之Spring(3)——Spring之AOP思想

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zl_StepByStep/article/details/80297971

     AOP面向切面编程——纵向重复,横向抽取

     典型的例子有:过滤器filter、拦截器interceptor、动态代理。

   动态代理:通过动态代理可以体现AOP思想;对目标对象中的方法方法进行增强。

      Spring能够为容器中管理的对象生成动态代理对象,以前我们要使用动态代理,我们需要自己调用下面这个方法:Proxy.newProxyInstatnce(classLoader , interface, invocationHandler )生成动态代理对象。即Spring能帮我们生成动态代理对象。


一、Spring AOP中的一些基本概念

1.1、代理

1.1.1、动态代理

     被代理对象必须要实现接口,才能产生代理对象,如果没有接口将不能使用动态代理技术。

      (有接口时,优先使用)

1.1.2、cglib代理

     这个代理技术是第三方代理技术,它可以对任何类生成代理,代理的原理是对目标对象进行继承代理,如果目标对象被final修饰,那么该类无法被cglib代理。(没有接口时使用)


Spring封装了动态代理代码,我们就不需要手写动态代理代码,还封装了cglib代理,两者结合可以对任何类进行增强。


扫描二维码关注公众号,回复: 3042816 查看本文章

1.2、名词解释

JoinPoint(连接点):目标对象中,所有可以增强的方法

Pointcut(切入点):目标对象,已经增强的方法。

Advice(通知/增强):增强的代码

Target(目标对象):被代理的对象

Wearing(织入):将通知应用到切入点的过程

Proxy(代理):将通知织入到目标对象后,形成的代理对象

aspect(切面):切入点+通知



二、Spring中的AOP演示

2.1、导包

一共十个jar包,之前导入了:4个Spring基础jar包+2个日志包,现在我们还要导入aop包和aspect包,还有两个外部依赖包,一个是aopalliance包,还有一个是aspectj-weaver包。





2.2、准备目标对象

定义一个类UserServiceImpl.java实现自定义的IUserService接口:

package com.zl.service;

public class UserServiceImpl implements IUserService {
	@Override
	public void save() {
		System.out.println("保存用户!");
	}
	@Override
	public void delete() {
		System.out.println("删除用户!");
	}
	@Override
	public void update() {
		System.out.println("更新用户!");
	}
	@Override
	public void find() {
		System.out.println("查找用户!");
	}
}


2.3、准备通知

package com.zl.aspect;

import org.aspectj.lang.ProceedingJoinPoint;

public class MyAdvice {
	
	//前置通知:目标方法运行之前调用
	public void before() {
		System.out.println("这是前置通知!");
	}
	
	//后置通知1(如果出现异常,将不会调用):在目标方法运行之后调用
	public void afterReturning() {
		System.out.println("这是后置通知(没有出现异常)!");
	}
	
	//环绕通知:在目标方法之前和之后都会调用
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("这是环绕通知之前的部分!");
		Object proceed = pjp.proceed(); //调用目标方法
		System.out.println("这是环绕通知之后的部分!");
		
		return proceed;
	}
	
	//异常拦截通知:如果出现异常就会调用
	public void afterException() {
		System.out.println("出现异常啦,调用异常拦截通知啦!");
	}
	
	//后置通知2(无论是否出现异常都会调用):在目标方法运行之后调用
	public void after() {
		System.out.println("这是后置通知(出现异常也会被调用)!");
	}
}

2.4、配置进行织入,将通知织入目标对象中

新建一个包和一个applicationContext.xml,在之前导入bean约束和context约束的基础上,再添加aop约束:

最后有以下三个约束:


applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns="http://www.springframework.org/schema/beans" 
	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-4.2.xsd 
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-4.2.xsd 
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
	<!-- 1.配置目标对象 -->
	<bean name="userServiceTarget" class="com.zl.service.UserServiceImpl"> </bean>
	
	<!-- 2.配置通知对象 -->
	<bean name="myAdvice" class="com.zl.aspect.MyAdvice"></bean>
	
	<!-- 3.配置将通知织入目标对象 -->
	<aop:config>
		<!--配置切入点 
			execution是表达式,id相当于指定切入点的名称 ,表示对目标对象里的delete方法进行切入/增强
			void com.zl.service.UserServiceImpl.delete()  public是可以省略的,默认就是public
			* com.zl.service.UserServiceImpl.delete()  	     不对返回值作任何要求
			* com.zl.service.UserServiceImpl.*()   	给UserServiceImpl类下的所有空参方法
			* com.zl.service.UserServiceImpl.*(..)  相比上一种,参数不作要求
			* com.zl.service.*ServiceImpl.*(..)  	相比上一种,找service下面,以ServiceImpl结尾的类下的所有方法
			* com.zl.service..*ServiceImpl.*(..)	相比上一种,service下的子包也会找
		-->
		<aop:pointcut expression="execution(* com.zl.service.*ServiceImpl.*(..))" id="pointcut"/>
		<aop:aspect ref="myAdvice">
			<!-- 指定名为before方法作为前置通知 -->
			<aop:before method="before" pointcut-ref="pointcut"/>
			<aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
			<aop:around method="around" pointcut-ref="pointcut"/>
			<aop:after-throwing method="afterException" pointcut-ref="pointcut"/>
			<aop:after method="after" pointcut-ref="pointcut"/>
		</aop:aspect>
	</aop:config>
</beans>

为了方便测试,我们将JUnit和Spring整合一下:

需要导入一个test的jar包:


编写Test类:

package com.zl.springaop;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.zl.service.IUserService;

//RunWith指定一个类,通过这个类的某个方法,帮我们创建容器
@RunWith(SpringJUnit4ClassRunner.class)

//指定创建容器时使用哪个配置文件
@ContextConfiguration("classpath:com/zl/springaop/applicationContext.xml")

public class TestAOP {
	//将名为userService的对象注入到userService变量中
	@Resource(name="userService")
	private IUserService userservice;
	@Test
	public void fun1() {
		userservice.delete();
	}
}

结果如下:


这个里面没有异常捕获通知,所以在 UserServiceImpl 类的delete( )方法里面末尾添加一个 int i = 1/0;   结果如下:


2.4、注解进行织入,将通知织入目标对象中


MyAdvice类

//表示该类是一个通知类
@Aspect
public class MyAdvice {
	//指定该方法是前置通知,指定切入点
	@Before("execution(* com.zl.service.*ServiceImpl.*(..)  )")
	//前置通知:目标方法运行之前调用
	public void before() {
		System.out.println("这是前置通知!");
	}
	
	@AfterReturning("execution(* com.zl.service.*ServiceImpl.*(..)  )")
	//后置通知1(如果出现异常,将不会调用):在目标方法运行之后调用
	public void afterReturning() {
		System.out.println("这是后置通知(没有出现异常)!");
	}
	
	@Around("execution(* com.zl.service.*ServiceImpl.*(..)  )")
	//环绕通知:在目标方法之前和之后都会调用
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("这是环绕通知之前的部分!");
		Object proceed = pjp.proceed(); //调用目标方法
		System.out.println("这是环绕通知之后的部分!");
		
		return proceed;
	}
	
	@AfterThrowing("execution(* com.zl.service.*ServiceImpl.*(..)  )")
	//异常拦截通知:如果出现异常就会调用
	public void afterException() {
		System.out.println("出现异常啦,调用异常拦截通知啦!");
	}
	
	@After("execution(* com.zl.service.*ServiceImpl.*(..)  )")
	//后置通知2(无论是否出现异常都会调用):在目标方法运行之后调用
	public void after() {
		System.out.println("这是后置通知(出现异常也会被调用)!");
	}
}

下述MyAdvice类,可以看出这个配置每一个里面都有相同的切点表达式 :("execution(* com.zl.service.*ServiceImpl.*(..)  )")

下面把切点抽取出来:






猜你喜欢

转载自blog.csdn.net/zl_StepByStep/article/details/80297971