欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring Aop详细讲解

程序员文章站 2022-07-12 16:42:55
...

目录

1、AOP概念
2、AOP的相关术语
3、AOP的环境搭建
4、AOP的底层两种实现
5、AOP的入门开发
6、AOP通知的类型
7、切入点表达式的写法

AOP概念

AOP:面向切面编程,根据软件重构的思想,如果多个类中出现相同的代码,将这些相同的代码提取到父类中,AOP通过横向抽取机制为这类无法通过纵向继承体系进行抽象的重复性代码提供了解决方案。

AOP的相关术语

1、连接点(JoinPooint):程序执行的某个特定位置,如类的开始初始化前,类的初始化后,类的某个方法调用前/后,方法抛出异常后。一个类或者一段代码拥有一些边界性质的特定点,这就是连接点。Spring仅支持方法的连接点,即仅能在方法调用前,方法调用后,方法抛出异常时及方法调用前后这些程序执行点织入增强;
2、切点(Pointcut):每个程序类都拥有多个连接点,在多个连接点中定位我们想要的连接点。AOP通过切点定位连接点,切点和连接点不是一对一的关系,一个切点可以匹配多个连接点。。
3、增强(Advice):增强是织入到目标类连接点上的一段程序代码,Spring中增强除了用于描述一段程序代码外,还拥有另一个和连接点相关的信息,执行点的方位。Spring 提供的接口都是带方位名的:BeforeAdvice、AfterReturningAdvice,等
4、目标对象(Target):增强逻辑的织入目标类
5、引介(Introduction):引介是特殊的增强,他为类添加一些属性和方法。
6、织入(Weaving):将增强添加到目标类的具体链接点的过程。
7、切面(Aspect):切面由切点和增强组成,他既包括横切逻辑的定义,也包括连接点的定义。

AOP的环境搭建

AOP相关的jar包:
spring Aop详细讲解

AOP的底层两种实现

1、jdk的动态代理:

package com.itheima.spring.cwj;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class spring_aop_jdk implements InvocationHandler{
	//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
  private userDao userdao;

public spring_aop_jdk(userDao userdao) {
	this.userdao = userdao;
}
  //产生userdao的代理方法
//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例    
//第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器  
//第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口  
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法  
//根据传入的目标返回一个代理对象  
public userDao createProxy(){
	userDao proxy =(userDao) Proxy.newProxyInstance(userdao.getClass().getClassLoader(), userdao.getClass().getInterfaces(),
			this);
	return proxy;
}
public 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);
}
}


Cglib的动态代理:

package com.itheima.spring.cwj1;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor{
 private customerDao customerdao;

public CglibProxy(customerDao customerdao) {
	super();
	this.customerdao = customerdao;
}
 //使用Cglib产生动态代理
public customerDao createProxy(){
 // 创建Cglib核心类对象
	Enhancer enhance = new Enhancer();
	//设置父类
	enhance.setSuperclass(customerdao.getClass());
	//设置回调(类似于InvocationHandler对象)
	enhance.setCallback(this);
	//创建代理对象
	customerDao proxy = (customerDao) enhance.create();
	return proxy;
}
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodproxy) throws Throwable {
	if("save".equals(method.getName())){
		System.out.println("监察");
		return methodproxy.invokeSuper(proxy, args);
	}
	return methodproxy.invokeSuper(proxy, args);
}
}

AOP的入门开发

1、环境搭建

spring Aop详细讲解ProductDao类

package com.itheima.spring.cwj2;

public interface ProductDao {
  public void save();
  public void update();
  public String delete();
}

ProductDaoImp类

package com.itheima.spring.cwj2;

public class ProductDaoImp implements ProductDao {

	public void save() {
   System.out.println("存储数据");
	}

	public void update() {
		   System.out.println("更新数据");
	}

	public String delete() {
		System.out.println("删除数据");
		return "chenwejie";
	}
}


切面类

package com.itheima.spring.cwj2;

import org.aspectj.lang.ProceedingJoinPoint;

public class myAspectXML {
	//前置通知
 public void check(){
	 System.out.println("校验-----------");
 }
 //后置通知
 public void writelog(Object result){
	 System.out.println("日志-----------"+result);
 }
 //环绕通知
 public Object aroud(ProceedingJoinPoint jointPoint) throws Throwable{
	 System.out.println("环绕前----");
	Object obj=jointPoint.proceed();//执行目标函数
	System.out.println("huanraohou------------");
	 return obj;
 }
 public void afterThrow(Throwable t){
	 System.out.println("异常通知"+t.getMessage());
	 
 }
}

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/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"> <!-- bean definitions here -->
  <!-- 配置目标对象,被增强的对象 -->
  <bean id="productdao" class="com.itheima.spring.cwj2.ProductDaoImp"></bean>
  <!-- 把切面类交给spring管理-->
   <bean id="myaspect" class="com.itheima.spring.cwj2.myAspectXML"></bean>
   <!-- 通过aop配置完成对目标类产生代理 -->
   <aop:config>
   <!--表达式配置那些类和那些方法需要进行增强  -->
     <aop:pointcut expression="execution(* com.itheima.spring.cwj2.ProductDaoImp.save(..))" id="pointcut1"/>
      <aop:pointcut expression="execution(* com.itheima.spring.cwj2.ProductDaoImp.delete(..))" id="pointcut2"/>
       <aop:pointcut expression="execution(* com.itheima.spring.cwj2.ProductDaoImp.update(..))" id="pointcut3"/>
   <!-- 配置切面 -->
   <aop:aspect ref="myaspect">
   <!-- 前置通知 -->
   <aop:before method="check" pointcut-ref="pointcut1"/>
    <!-- 后置通知-->
    <aop:after-returning method="writelog" pointcut-ref="pointcut2" returning="result"/>
    <!-- 环绕通知 -->
    <aop:around method="aroud" pointcut-ref="pointcut3"/>
    <!--异常通知  -->
    <aop:after-throwing method="需要在切面类中定义的方法" pointcut-ref="需要在前面配置那些类和方法需要增强"/>
   </aop:aspect>
   </aop:config>
</beans>

测试类

package com.itheima.spring.cwj2;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.ImportResource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
//spring配合junit使用,需要导入包spring-text-4.2.4.release
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class springdemo3 {
	@Resource(name="productdao")
	private ProductDao productdao;
	@Test
	public void demo(){
		productdao.save();
		productdao.delete();
		productdao.update();
	}
}

运行结果
spring Aop详细讲解

AOP通知的类型

1.前置通知
2.环绕通知
3.后置通知
4.异常通知
5.最终通知

切入点表达式的写法

1、execution()::表达式主体,访问修饰符可以省略。
2、第一个*号:表示返回类型, 号表示所有的类型。
3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service包、子孙包下所有类的方法。
4、第二个
号:表示类名,号表示所有的类。
5、
(…):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。