【Spring之AOP】

本文详细介绍了面向切面编程(AOP)的概念、发展历程、术语、原理剖析及实现方法,包括静态AOP与动态AOP的区别,以及如何通过Spring框架实现AOP功能。文章还解释了AOP在提高代码复用性和降低耦合度方面的作用,并提供了使用AOP的步骤和示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是AOP?

-面向切面编程
-它是一种思想,可在不改变程序源码的情况下为程序添加额外的功能。

-允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发。应用对象只实现业务逻辑即可,并不负责其他的系统级关注点。

-AOP专门用于处理系统中分布于各个模块中的交叉关注点的问题,在J2EE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。


AOP的发展过程?

-静态AOP:Aspect形式,通过特定的编译器,将实现后的Aspect编译并织入到系统的静态类中

-动态AOP:AOP的织入过程在系统运行开始之后进行,而不是预先编译到系统中


AOP术语?

-连接点:程序执行的某个特定位置,比如类初始化前、类初始化后、方法调用前、方法调用后等

-切点:通过切点来定位特定的连接点

-增强:织入到目标类连接点上的一段程序代码

-目标对象:增强逻辑的织入目标类

-引介:是一种特殊的增强,它为类添加一些属性和方法

-织入:为增强添加目标类的具体连接点上的过程

-代理:一个类被AOP织入增强后,会产生一个结果类,该类融合了原类和增强逻辑的代理类

-切面:由切点和增强组成,既包括了横切逻辑的定义,也包括了连接点的定义


AOP的原理剖析?

-AOP代理其实是由AOP框架动态生成的一个对象,该对象可作为目标对象使用,AOP代理所包含的方法与目标对象的方法如下图所示:


使用AOP的步骤是:

定义普通业务组件 ---> 定义切入点 ---> 定义增强处理


代理对象的方法 = 增强处理 + 被代理对象的方法


AOP的通俗理解?

-一个组件A,不关心其他常用的服务组件B,但是这个组件A使用组件B的时候,不是组件A自身去调用,而是通过配置等其他方式,比如Spring中可以通过xml配置文件。这样就使得A压根就不需要知道服务组件B是怎样的,爱存在不存在,爱怎么存在都与A无关。A只关心自己的业务逻辑,具体A使用B的时候,配置文件去做,与具体的A组件无关。


AOP的实现方法?

(1)利用Proxy实现AOP功能 (JDK动态代理)

采用Proxy类方法,基本流程为:主函数--->代理--->目标对象的方法。对于Proxy类有一个使用前提,就是目标对象必须实现接口,否则不能使用这个方法。

实现AOP功能步骤如下:

创建接口:StudentInterface.java

创建接口实现类:StudentBean.java

创建代理工厂:ProxyFactory.java

public interface StudentInterface {
	
	public void print();
	
}


public class StudentBean implements StudentInterface {

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public StudentBean() {
	}

	public StudentBean(String name) {
		super();
		this.name = name;
	}

	@Override
	public void print() {
		System.out.println("hi student.");
	}

}

public class ProxyFactory implements InvocationHandler {

	private Object object;

	public Object createStudentProxy(Object obj) {
		this.object = obj;
		//创建并返回代理
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
				.getClass().getInterfaces(), this);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		StudentBean studentBean = (StudentBean) object;
		Object obj = null;
		if(studentBean.getName() != null){
			obj = method.invoke(object, args);
		}else{
			System.out.println("学生姓名为空,代理类已经进行拦截.");
		}
		return obj;
	}

}

public class Test001 {

	public static void main(String[] args) {
		StudentInterface s1 = new StudentBean();
		ProxyFactory proxyFactory = new ProxyFactory();
		StudentInterface s2 = (StudentInterface) proxyFactory
				.createStudentProxy(s1);
		s2.print();
	}
}


总结:

目标对象必须实现接口

返回创建的代理对象

重写invoke()方法

限制条件放在invoke()方法中



(2)利用CGLIB实现AOP功能(CGLIB动态代理)

CGLIB(code generation library)是一个开源项目,它是一个强大的、高性能、高质量的code生成类库,它可以在运行期间扩展Java类和实现Java接口。

实现AOP功能步骤如下所示:

引入jar包

创建实体类

创建CGLIB代理类

创建入口类进行测试

public class StudentBean {

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public StudentBean() {
	}

	public StudentBean(String name) {
		super();
		this.name = name;
	}

	public void print() {
		System.out.println("hi student.");
	}

}

public class CGLIBProxyFactory implements MethodInterceptor{

	private Object object;
	
	public Object createStudentProxy(Object obj){
		this.object = obj;
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(obj.getClass());
		enhancer.setCallback(this);
		return enhancer.create();
	}
	

	@Override
	public Object intercept(Object proxy, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable {
		StudentBean stu  = (StudentBean) object;
		Object ret = null;
		if(stu.getName() != null){
			methodProxy.invoke(object, args);
		}else{
			System.out.println("学生姓名为空,方法已经被拦截.");
		}
		return ret;
	}

}

public class Test002 {
	
	public static void main(String[] args) {
		
		StudentBean s1 = new StudentBean();
		CGLIBProxyFactory cglibProxyFactory = new CGLIBProxyFactory();
		StudentBean s2 = (StudentBean) cglibProxyFactory.createStudentProxy(s1);
		s2.print();
		
	}

}


(3)利用Spring XML文件配置方式实现AOP功能步骤如下:

引入jar包

配置AOP命名空间

创建目标对象类

创建切面

在配置文件中配置

创建入口类进行测试


public interface TrainStationAware {
	
	//售票方法
	public String sellTicket(String name);
	
	//退票方法
	public String returnTicket(String name);
}


public class TrainStation implements TrainStationAware{

	@Override
	public String sellTicket(String name) {
		System.out.println(name + "购票成功");
		return "ok";
		
	}

	@Override
	public String returnTicket(String name) {
		System.out.println(name + "退票成功");
		return "ok2";
	}

}

public class XmlAdvice {

	/**
	 * 在核心业务执行前执行,不能阻止核心业务的调用。
	 * 
	 * @param joinPoint
	 */
	private void doBefore(JoinPoint joinPoint) {
		System.out.println("-----doBefore().invoke-----");
	}

	/**
	 * 手动控制调用核心业务逻辑,以及调用前和调用后的处理,
	 * 
	 * 注意:当核心业务抛异常后,立即退出,转向After Advice 执行完毕After Advice,再转到Throwing Advice
	 * 
	 * @param pjp
	 * @return
	 * @throws Throwable
	 */
	private Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("-----doAround().invoke-----");
		MethodSignature ms = (MethodSignature) pjp.getSignature();
		Method method = ms.getMethod();
		Object retVal = null;
		if("returnTicket".equals(method.getName())){
			System.out.println("代理售票点不能办理退票");
		}else{
			retVal = pjp.proceed();
		}
		 
		System.out.println("-----End of doAround()------");
		return retVal;
	}

	/**
	 * 核心业务逻辑退出后(包括正常执行结束和异常退出),执行此Advice
	 * 
	 * @param joinPoint
	 */
	private void doAfter(JoinPoint joinPoint) {
		System.out.println("-----doAfter().invoke-----");
	}

	/**
	 * 核心业务逻辑调用正常退出后,不管是否有返回值,正常退出后,均执行此Advice
	 * 
	 * @param joinPoint
	 */
	private void doReturn(JoinPoint joinPoint) {
		System.out.println("-----doReturn().invoke-----");
	}

	/**
	 * 核心业务逻辑调用异常退出后,执行此Advice,处理错误信息
	 * 
	 * @param joinPoint
	 * @param ex
	 */
	private void doThrowing(JoinPoint joinPoint, Throwable ex) {
		System.out.println("-----doThrowing().invoke-----");
		System.out.println(" 错误信息:" + ex.getMessage());
	}

}

<?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-2.0.xsd  
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">  
               
      
    <bean id="trainStationAware" class="com.bear.spring.aop.TrainStation"/>  
      
    <bean id="xmlHandler" class="com.bear.spring.aop.XmlAdvice" />  
   
    <aop:config>  
        <aop:aspect id="aspect" ref="xmlHandler">  
            <aop:pointcut id="pointUserMgr" expression="execution(* com.bear.spring.aop.*.*Ticket(..))"/>  
            <aop:before method="doBefore"  pointcut-ref="pointUserMgr"/>  
            <aop:after method="doAfter"  pointcut-ref="pointUserMgr"/>  
            <aop:around method="doAround"  pointcut-ref="pointUserMgr"/>  
            <aop:after-returning method="doReturn"  pointcut-ref="pointUserMgr"/>  
            <aop:after-throwing method="doThrowing" throwing="ex" pointcut-ref="pointUserMgr"/>  
              
        </aop:aspect>  
    </aop:config>  
</beans> 

	@Test
	public void test(){
		ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
		TrainStationAware tsa = (TrainStationAware) context.getBean("trainStationAware");
		
		tsa.sellTicket("张三");
//		tsa.returnTicket("李四");
		
	}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值