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

spring AOP

程序员文章站 2022-07-12 14:19:13
...

  Spring AOP(面向切面编程):    

    

    那么切面(aspect)是啥?

    一个关注点的模块化,通常是一个类;通常会横切多个对象;

   再来说说为什么要有aop,我们都知道java是面向对象的语言,3大特性,封装、继承、多态。我们使用类来区别不同兑现,类是对一类“事物”的属性与行为的抽象。那么现在我们我们需要做一个日志系统,来记录操作,输出日志信息这个功能并不是其它类的属性或者行为,也就是和其他类并没有太多的关系,因此我们需要写一个日志类,那么问题来了!!既然是日志,系统中肯定有许多地方需要用到,那么在需要用到的地方,我们就需要调用,一旦需要修改的时候,极为不便,那么面向切向编程(AOP)就可以很好的解决这个问题!

    

  理解:Aop就是将动态代理封装了起来,只用写好的真实对象,和额外实现的方法也就是公共业务,在不改变源代码的基础上,插入了功能,实现了公共业务的重复利用,这样也提高了开发效率;


现在来看看spring aop 的一些名词:

关注点:增加的某个业务,例如:日志,安全,事务等;

切面(aspect):一个关注点的模块化,通常是一个类;通常会横切多个对象;

连接点(JoinPoint):某个方法的执行

通知(advice):在切面的某个连接点上执行的特定的动作。包括了aroundbeforeAfter等不同类型的通知;

织入(Weaving):把切面连接其它的应用程序类型或者对象上,并创建一个被通知的对象

使用spring实现aop

支持:java 5.0引入了java.lang.instrument,允许在jvm启动时启用一个代理类,通过该代理类在运行期间修改类的字节码,改变一个类的功能,实现AOP功能;

第一种是实现方式-通过spring APi来实现:

    实现MethodBeforeAdvice接口:

public class Log implements MethodBeforeAdvice{
	/**
	 * @param method 被调用方法对象
	 * @param args 被调用的方法的参数
	 * @param target 被调用的方法的目标对象
	 * */
	@Override
	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被执行");
	}
}
spring AOP
配置文件使Log类和对应的类进行关联;
<?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 id="userService" class="com.ccc.service.impl.UserServiceImpl"/>
    <bean id="log" class="com.ccc.log.Log"/>
    <aop:config>
    	<aop:pointcut expression="execution(* com.ccc.service.impl.UserServiceImpl.add())" id="pointcut"/>
    	<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

 com.ccc.service.impl.UserServiceImpl.add()

execution中为被切的对象方法,可以想象成把日志功能横切嵌入进去

.add()表示add方法, 表示所有方法可以用.*() ()表示无参数,而有参可以用(..)表示所有个数的参数

运行结果:

com.ccc.service.impl.UserServiceImpl的add方法被执行
增加用户

第二种实现方式:通过自定义类来实现

public class UserService {
	public void add(){
		System.out.println("i  am  add method");
	}
	public void delete(){
		System.out.println("i am  delete method");
	}

public class Log {
	public void beforelog(){
		System.out.println("i am beforelog");
	}
	public void afterlog(){
		System.out.println("i am afterlog");
	}
}

配置文件:

<bean id="service" class="com.czy.service.UserService"/>
    <bean id="log" class="com.czy.log.Log"/>
    <aop:config>
    	<aop:aspect ref="log"><!--引入切面类-->
    		<aop:pointcut expression="execution(* com.czy.service.UserService.*())" id="pointcut"/>
    		<aop:before method="beforelog"  pointcut-ref="pointcut"/>
    	</aop:aspect>
    </aop:config>


spring AOP

spring AOP

可以看出在执行add方法的时候,拦截器拦截,先输出了日志;

第三种方式:通过注解实现aop

说实话,个人感觉前两种配置文件太繁琐了.....第三中方法的配置文件如下(头部dtd约束省略):

<bean id="service" class="com.czy.service.UserService"/>
    <bean id="log" class="com.czy.log.Log"/>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

这样就一条....使用spring的配置自动完成创建代理织入切面的工作。

//表示这是一个切面
@Aspect    
public class Log {
	@Before("execution(* com.czy.service.UserService.*())")
	public void beforelog(){
		System.out.println("i am beforelog");
	}
	public void afterlog(){
		System.out.println("i am afterlog");
	}
}

注解:  @Aspect:表示这是一个切面

            @Before:在方法执行前执行

            @Around:环绕,在前后都执行一次

//表示这是一个切面
@Aspect    
public class Log {
	@Before("execution(* com.czy.service.UserService.*())")
	public void beforelog(){
		System.out.println("i am beforelog");
	}
@After("execution(* com.czy.service.UserService.*())")
	public void afterlog(){
		System.out.println("i am afterlog");
	}

环绕通知与前置后置通过不同,需要带一个参数

@Around("execution(* com.czy.service.UserService.*())")
	public void aroundlog(ProceedingJoinPoint pjp){
		System.out.println("abefore log");
		System.out.println(pjp.getSignature());
		System.out.println("aafter log");

运行结果:

spring AOP


上一篇: Spring AOP

下一篇: spring AOP