切面编程-自定义注解方式进行切点拦截

切面编程(AOP)是基于动态代理的一种编程,它是把不同对象的共同功能摘出来,通过切点触发的形式进行调用,切点可以是对象,可以是注解等。通过切面编程,可以降低代码的耦合性。

例如,日志的打印,银行系统中,所有进行了存取款的操作,需要进行日志的打印。

写一个例子

在pom.xml中添加依赖

<dependency>
   	<groupId>org.aspectj</groupId>
  	<artifactId>aspectjweaver</artifactId>
    	<version>1.9.2</version>
</dependency>
<dependency>
    	<groupId>aspectj</groupId>
    	<artifactId>aspectj-tools</artifactId>
    	<version>1.0.6</version>
</dependency>

创建一个接口

package com.test.sprintboot;

public interface Flyable {
	void fly();
}

写一个自定义注解,切点通过注解的方式进行拦截

package com.test.sprintboot.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value = {ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
	String value();
}

创建一个接口的实现类

package com.test.sprintboot.services;

import org.springframework.stereotype.Component;

import com.test.sprintboot.Flyable;
import com.test.sprintboot.annotation.Value;

@Component

public class Parrot implements Flyable {

	@Override
	@Value(value="18")
	public void fly() {
		System.out.println("鹦鹉在飞翔...");
        
	} 

}

切面

package com.test.sprintboot;


import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import com.test.sprintboot.annotation.Value;

@Aspect
@Component
public class AspectDemo {
	
	public AspectDemo(){
		
	}	

	@Pointcut("@annotation(com.test.sprintboot.annotation.Value)")//匹配方法上有对应注释
	
	public void targetValue(){
		
	}
	
	@Around("targetValue()")
	public void aroundTarget(ProceedingJoinPoint joinPoint) throws Throwable{
		Class<?> aclass = joinPoint.getTarget().getClass();
		String name = joinPoint.getSignature().getName();
		MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();	
		Class[] parameterType = methodSignature.getParameterTypes();
		Method method = aclass.getMethod(name, parameterType);		
		joinPoint.proceed();

	}
}

调用方法

package com.test.sprintboot;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.test.sprintboot.services.Eagle;
import com.test.sprintboot.services.Parrot;
import com.test.sprintboot.services.Prox;



/**
 * Hello world!
 *
 */
@RestController
public class App 
{
	
	@RequestMapping("/parrot")
	public void parrot(){
		ApplicationContext contxt = new ClassPathXmlApplicationContext("applicationContext.xml");
		Parrot parrot = contxt.getBean(Parrot.class);
		parrot.fly();
	}
}

自此,一个简单的通过注解进行拦截的切面的代码就写好了,通过控制台调用localhost:8080/parrot即可进行调用(端口根据自己springboot的端口进行修改)

 

 

1、“within(com.elim.spring.aop.service.UserServiceImpl)”匹配UserServiceImpl类对应对象的所有方法外部调用,而且这个对象只能是UserServiceImpl类型,不能是其子类型。

2、“within(com.elim..*)”匹配com.elim包及其子包下面所有的类的所有方法的外部调用。

 

1、“@within(com.elim.spring.support.MyAnnotation)”匹配被调用的方法声明的类上拥有MyAnnotation注解的情况。比如有一个ClassA上使用了注解MyAnnotation标注,并且定义了一个方法a(),那么在调用ClassA.a()方法时将匹配该Pointcut;如果有一个ClassB上没有MyAnnotation注解,但是它继承自ClassA,同时它上面定义了一个方法b(),那么在调用ClassB().b()方法时不会匹配该Pointcut,但是在调用ClassB().a()时将匹配该方法调用,因为a()是定义在父类型ClassA上的,且ClassA上使用了MyAnnotation注解。但是如果子类ClassB覆写了父类ClassA的a()方法,则调用ClassB.a()方法时也不匹配该Pointcut。

 

1、“execution(* add())”匹配所有的不带参数的add()方法。

2、“execution(public * com.elim..*.add*(..))”匹配所有com.elim包及其子包下所有类的以add开头的所有public方法。

3、“execution(* *(..) throws Exception)”匹配所有抛出Exception的方法。

 

1、“target(com.elim.spring.aop.service.IUserService)”则匹配所有被代理的目标对象能够转换为IUserService类型的所有方法的外部调用。

 

1、“@target(com.elim.spring.support.MyAnnotation)”匹配被代理的目标对象对应的类型上拥有MyAnnotation注解时。

args用来匹配方法参数的。

1、“args()”匹配任何不带参数的方法。

2、“args(java.lang.String)”匹配任何只带一个参数,而且这个参数的类型是String的方法。

3、“args(..)”带任意参数的方法。

4、“args(java.lang.String,..)”匹配带任意个参数,但是第一个参数的类型是String的方法。

5、“args(..,java.lang.String)”匹配带任意个参数,但是最后一个参数的类型是String的方法。

 

1、“@args(com.elim.spring.support.MyAnnotation)”匹配方法参数类型上拥有MyAnnotation注解的方法调用。如我们有一个方法add(MyParam param)接收一个MyParam类型的参数,而MyParam这个类是拥有注解MyAnnotation的,则它可以被Pointcut表达式“@args(com.elim.spring.support.MyAnnotation)”匹配上。

 

 

1、“@annotation(com.elim.spring.support.MyAnnotation)”匹配所有的方法上拥有MyAnnotation注解的方法外部调用。

 

 

bean用于匹配当调用的是指定的Spring的某个bean的方法时。

1、“bean(abc)”匹配Spring Bean容器中id或name为abc的bean的方法调用。

2、“bean(user*)”匹配所有id或name为以user开头的bean的方法调用。

 

表达式组合使用

1、“bean(userService) && args()”匹配id或name为userService的bean的所有无参方法。

2、“bean(userService) || @annotation(MyAnnotation)”匹配id或name为userService的bean的方法调用,或者是方法上使用了MyAnnotation注解的方法调用。

3、“bean(userService) && !args()”匹配id或name为userService的bean的所有有参方法调用。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值