[Spring]AOP切面编程/原理/基于注解/基于xml

AOP概念

不讲废话,面向切面就比如说有很多个业务逻辑代码,如果你要修改代码,在代码实现前后增加一条逻辑,比如要判断后才执行代码,你总不能一条条去改各个类的代码。

所以切面就是说执行一个方法,这个方法变为一个切入点来配置,你可以定义这个切入点,你想在执行这个方法之前增加逻辑或者在它之后增加逻辑,都可自行配置。

原理(Proxy&CGlib)

Proxy实现(JDK的AOP,不是框架里的)

定义一个代理工厂拦截了业务bean,先判断。

package com.yiki.service;

public interface PersonSercvice {
	public void save(String name);
	public void update(String name,Integer pid);
	public String getPname(Integer pid);
	
	
}
package com.yiki.bean;

import com.yiki.service.PersonSercvice;

public class Person implements  PersonSercvice{
	private String user = null;	
	
	public Person() {
	}
	
	public Person(String user) {
		this.user=user;
	}

	
	
	public String getUser() {
		return user;
	}

	@Override
	public void save(String name) {
System.out.println("save'");		
	}

	@Override
	public void update(String name, Integer pid) {
System.out.println("update");		
	}

	@Override
	public String getPname(Integer pid) {
		// TODO Auto-generated method stub
		return "getname";
	}

}
package com.yiki.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.aopalliance.intercept.Invocation;

import com.yiki.bean.Person;

public class JDKProxyFactory implements InvocationHandler {
	private Object target;

	public Object createProxyInstance(Object target) {

		this.target = target;
		Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);

		return target;

	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Person bean = (Person) this.target;

		Object result = null;
		if (bean.getUser() != null) {

			result = method.invoke(target, args);
		}

		return result;
	}

}
package com.yiki.test;

import org.junit.Test;

import com.yiki.aop.JDKProxyFactory;
import com.yiki.bean.Person;
import com.yiki.service.PersonSercvice;

public class aoptest {

	@Test
	public void testProxy(){
		JDKProxyFactory proxy = new JDKProxyFactory();
		PersonSercvice service	 = (PersonSercvice) proxy.createProxyInstance(new Person("yiki"));
		service.save("888");
		
		//PersonSercvice service	 = (PersonSercvice) proxy.createProxyInstance(new Person());没有输出
	}
	
}

Spring cglib实现

package com.yiki.aop;

import java.lang.reflect.Method;

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

import com.yiki.bean.People;
import com.yiki.bean.Person;

public class cglibFactory implements MethodInterceptor {
	private Object target;

	public Object createProxyInstance(Object target) {
		
		this.target=target;
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(this.target.getClass());
		enhancer.setCallback(this);
		
		
		return enhancer.create();
		
	}

	@Override
	public Object intercept(Object arg0, Method method, Object[] args, MethodProxy methodproxy) throws Throwable {
		People bean = (People) this.target;

		Object result = null;
		if (bean.getUser() != null) {

			result = methodproxy.invoke(target, args);
		}

		return result;

	}
}
package com.yiki.bean;

public class People {//不需要实现接口
	private String user;
	
	public People() {
	}

	public People(String user) {
		this.user = user;
	}

	public String getUser() {
		return user;
	}

	public void save(String name) {
		System.out.println("save'");
	}

}
@Test
	public void testcglib(){
		cglibFactory cglib = new cglibFactory();
		People people = (People) cglib.createProxyInstance(new People("yiki"));//为空则不输出
		people.save("000");
		
	}

框架实现

Spring AOP注解实现(真正的Spring框架实现)

这里只涉及最普通的注解,具体切面的匹配(就是@PointCut(匹配规则))以及一些需要传入参数(&&args)的情况要另算……(太多了不知道怎么写- -。)

首先这里要先把配置文件自动扫描给加上。

<?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"
	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-4.2.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">

	<context:annotation-config />

<!-- 自动扫描所有的bean -->
	<context:component-scan base-package="com.yiki.bean" />
	
<!-- 声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面 -->
	<aop:aspectj-autoproxy />

</beans>

这里我已经不会在配置文件写bean了,而是用@Compenent

package com.yiki.bean;

import org.springframework.stereotype.Component;

@Component
public class Student {
	
	public void student(){
		System.out.println("student");
	}
	
	

}

切面类

package com.yiki.bean;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class aspect {
    @Pointcut("execution (* com.yiki.bean.Student.*(..))")//匹配Student下的所有方法
	private void anyMethod() {
	}// 空方法,是一个切入点

	@Before("anyMethod()")
	public void before() {
		System.out.println("before前置通知");
	}

	@AfterReturning("anyMethod()")
	public void after() {
		System.out.println("afterReturning后置通知");
	}
	
	@After("anyMethod()")
	public void doAfter(){
		System.out.println("after最终通知");
		
	}
	@Around("anyMethod()")//适合权限控制,万能~~~~~
	public Object around(ProceedingJoinPoint pjp) throws Throwable{
		
		Object result = pjp.proceed();
		try {
			//=AfterReturning
		} catch (Exception e) {
			// =before
		}finally {
			//后置通知
		}
		
		System.out.println("around环绕通知");
		return result;//最终
	}
		

}

测试

package com.yiki.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.yiki.bean.Student;

public class tests {
	
	public static void main(String[] args) {
		String xmlPath = "ApplicationContext.xml";
		ApplicationContext cfg = new ClassPathXmlApplicationContext(xmlPath);
		Student stu = (Student) cfg.getBean("student");
		stu.student();
		
		
	}

}

基于xml配置文件的AOP(只支持单例模式)

遵循以下原则:

        <bean id="student" class="com.yiki.bean.Student"></bean>
	<bean id="aspect" class="com.yiki.bean.aspect"></bean>

	<!-- 把student作为一个切面声明,这个切面的名字是aspectAOP 
	【expression】里写需要匹配的方法,*后面有空格
	-->
	<aop:config>
		<aop:aspect id="aspectAOP" ref="aspect">
			<aop:pointcut id="doOne" expression="execution(* com.yiki.bean.Student.*(..))"  />
		</aop:aspect>
	</aop:config>

对于切入点PointCut:execution(这里自己查官方吧,很多匹配规则)

<?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-3.0.xsd 
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

	<!-- bean definition & AOP specific configuration -->


	<bean id="student" class="com.yiki.bean.Student"></bean>
	<bean id="aspect" class="com.yiki.bean.aspect"></bean>

	<!-- 把aspect作为一个切面声明,这个切面的名字是aspectAOP 
	切入点是student里的所有方法,==》【expression】里写需要匹配的方法,*后面有空格
	-->
	<aop:config>
		<aop:aspect id="aspectAOP" ref="aspect">
			<aop:pointcut id="doOne" expression="execution(* com.yiki.bean.Student.*(..))"  />
		
		<!-- advice通知配置 -->
		<aop:before method="before" pointcut-ref="doOne"/>
		<aop:after-returning method="after" pointcut-ref="doOne"/>
		<aop:around method="around" pointcut-ref="doOne"/>
		
		
		</aop:aspect>
	</aop:config>

</beans>
package com.yiki.bean;

import org.aspectj.lang.ProceedingJoinPoint;

public class aspect {
	
	public void show(){
		
		System.out.println("aspect");
		
	}
	
	public void before() {
		System.out.println("before前置通知");
	}

	public void after() {
		System.out.println("afterReturning后置通知");
	}
	
	public void doAfter(){
		System.out.println("after最终通知");
		
	}
	public Object around(ProceedingJoinPoint pjp) throws Throwable{
		
		Object result = pjp.proceed();
		try {
			//=AfterReturning
			System.out.println("之后Runing环绕通知");
		} catch (Exception e) {
			// =before
			System.out.println("之前环绕通知");
		}finally {
			//后置通知
			System.out.println("之后环绕通知");
		}
		
		System.out.println("around环绕通知");
		return result;//最终
	}
	

}

    原文作者:AOP
    原文地址: https://blog.csdn.net/qq_38277033/article/details/80426254
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞