spring关于面向切面编程AOP的操作

首先说明:用一个要在进行增删改操作的时候进行日志信息添加的操作来介绍AOP

需要的jar包:aspectjrt、aspectjweaver、spring-context

<!-- 引入第3方的切面框架AspectJrt的相关JAR文件 -->
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjrt</artifactId>
	<version>${aspect.version}</version>
</dependency>

<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>${aspect.version}</version>
</dependency>


<!-- 导入spring容器相关JAR文件 -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>${spring.version}</version>
</dependency>

 

1、首先需要在spring配置文件applicationContext.xml中进行相应的配置

配置<aop:aspectj-autoproxy/>这样一句话

<?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:p="http://www.springframework.org/schema/p"
	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-3.0.xsd
						http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<!-- 开启spring容器的自动扫描功能 -->
	<context:component-scan base-package="com.ali.springaop"></context:component-scan>

	<!-- 开启切面的动态代理支持 -->
	<aop:aspectj-autoproxy/>
</beans>

2、编写AOP类(切入点定位在某个方法上)这个不是日志操作代码,只是介绍怎样编写

1)该类使用@Aspect注解声明为一个切面对象,同时使用@Component注解将这个类丢进spring容器

2)写一个方法作为切入点,在该方法上写上@Pointcut注解定义切入点在哪

3)设置通知方式,写一个方法,在方法上写上@Before这种类型的通知注解,需要哪些视情况而定。


/**
 * 该类主要完成切面功能的演示
 * @Aspect 表示将一个Java类定义为一个切面
 * 一个切面就是一个业务交叉功能的处理面
 * @author Administrator
 *
 */
//@Component
//@Aspect
public class DemoAspectJ {

	/**
	 * @Pointcut制定切入点 切面关注对象的标准
	 * 
	 * execution()主要用来定义   切面上的通知(代码),什么时候可以开启执行
	 * 语法格式:execution(访问修饰符? 返回类型  包结构.类结构? 方法名(参数列表) 抛出的异常?)
	 * 
	 * ?代表可以省略
	 * 
	 *     * 表示通配        ..表示0-N个参数
	 * 
	 */
	@Pointcut("execution(* com.gezhi.springaop.*mag.service.impl.*ServiceImpl.*(..))")
	public void pointcut() {}
	
	/**
	 * 前置通知
	 * @param point 固定参数  连接点(代表的是:切面 和 正在执行的目标方法 取得连接的一个点)
	 */
	@Before("pointcut()")
	public void beforeAdvice(JoinPoint point) {
		Object obj = point.getTarget();//获得目标对象(代理对象)
		String method = point.getSignature().getName();//获取正在执行的目标方法
		Object[] params = point.getArgs();//获得目标方法获取到的参数
		
		
		System.out.println("目标对象是" + obj);
		System.out.println("目标方法是" + method);
		System.out.println("获取到的参数是" + Arrays.toString(params));
		
		//通过反射取得目标对象的类对象
		Class<?> cls = obj.getClass();
		try {
			Field f = cls.getDeclaredField("encoding");
			f.setAccessible(true);//设置私有属性更改权限
			f.set(obj, "utf-8");
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		
		System.out.println("我是前置通知,我执行在" + method + "执行之前!");
	}
	
	
	
	/**
	 * @AfterReturning 定义后置返回通知,该通知执行在目标方法 正常执行之后
	 * @param point 连接点
	 * @param obj 返回对象
	 */
	@AfterReturning(pointcut="pointcut()",returning="ret")
	public void afterReturningAdvice(JoinPoint point,Object ret) {
		String method = point.getSignature().getName();//获取正在执行的目标方法
		System.out.println("后置返回通知,我执行在"+method+"正常执行之后,我收到的返回是:" + ret);
		
	}
	
	/**
	 * @AfterThrowing 定义后置异常通知,该通知执行在目标方法 抛出异常之后
	 * @param point
	 * @param e
	 */
	@AfterThrowing(pointcut="pointcut()",throwing="e")
	public void afterThrowingAdvice(JoinPoint point,Exception e) {
		
		System.out.println("我是后置异常通知,我接收的异常是:" + e);
	}
	
	/**
	 * @After 定义后置通知 ,该通知对象,不管目标方法是否正常执行成功,该通知都要执行
	 * 该通知执行在@AfterThrowing || @AfterReturning 之前
	 * @param point
	 */
	@After("pointcut()")
	public void afterAdvice(JoinPoint point) {
		System.out.println("我是后置通知,我执行在目标方法返回结果或异常之前!");
	}
	
	
	
	
	@Around("pointcut()")
	public Object aroundAdive(ProceedingJoinPoint point) {
		Object obj = point.getTarget();//获得目标对象(代理对象)
		String method = point.getSignature().getName();//获取正在执行的目标方法
		Object[] params = point.getArgs();//获得目标方法获取到的参数
		
		params[0] = new UserBean();//可以修改参数
		Object ret = null;
		try {
			ret = point.proceed(params);//还可以控制目标方法的执行
			
			ret = new UserBean();//可以修改返回
			
			
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return ret;
	}
	
}

2、编写AOP类(切入点定位在某个注解上)这个是关于日志操作的

下面是定位到@MyLog注解上

@Component
@Aspect
public class OptLogAspectJ {

	@Resource
	private IOptLogService optLogServiceImpl;
	
	
	@Pointcut("@annotation(com.ali.springaop.anno.MyLog)")
	public void pointcut() {}
	
	
	/**
	 * @annotation(mylog) 表示将@MyLog 对象作为参数,传递到mylog形参中,使用&& @annotation(mylog)的方式可以更简单的去获取注解的内容
	 * @param point
	 * @param mylog
	 * @param ret
	 */
	@AfterReturning(pointcut="pointcut() && @annotation(mylog)",returning="ret")
	public void afterReturningAdvice(JoinPoint point,MyLog mylog, Object ret) {
		Object[] args = point.getArgs();//获得目标方法的参数
		
		OptLogBean log = new OptLogBean();//实例化日志javabean
		
		//从注解中获取注解属性的值
		log.setMenuName(mylog.value());
		log.setOptType(mylog.type().getValue());
		
		log.setOptTime(new Date());
		log.setUserName("");
		log.setOptData(Arrays.toString(args));
		
        //日志信息添加
		optLogServiceImpl.addOptLogBean(log);
		
	}
	
}

那么在方法上就要有相应的注解:

/**
 * @Service 表示该Java类是一个需要被spring容器管理起来的业务层的组件
 * 默认情况下,spring容器扫描到该组件之后,将会将该类的类名 “首字母小写后的字符串”,作为该组件在容器中的ID
 * 当然你也可以通过@Service("sb")这种方式去改
 * @author Administrator
 *
 */
@Service
public class UserServiceImpl implements IUserService {
	
	/**
	 * @Autowired 代表自动装配,只不过它默认采用的装配方式是byType
	 * @Qualifier 代表精准装配,改byType为byName
	 */
//	@Autowired
//	@Qualifier("userDaoImpl3")
	
	/**
	 * @Resource 约== @Autowired + @Qualifier
	 * 默认情况下,@Resource将先按照byName装配方式进行精准装配,如果装配失败,将回退到byType装配方式
	 * 
	 * 如果你指定了name="userDaoImpl3" ,那么将严格按照byName的装配方式,不会回退
	 */
	@Resource
	private IUserDao userDaoImpl;
	
	@MyLog(value="用户管理",type=LogEnum.ADD)
	@Override
	public UserBean saveUserBean(UserBean user) {
		// TODO Auto-generated method stub
		return userDaoImpl.addUserBean(user);;
	}

	@MyLog(value="用户管理",type=LogEnum.ADD)
	@Override
	public int addBatchUserBean(List<UserBean> users) {
		// TODO Auto-generated method stub
		return userDaoImpl.addBatchUserBean(users);
	}

	@MyLog(value="用户管理",type=LogEnum.UPDATE)
	@Override
	public int updateUserBean(UserBean user) {
		// TODO Auto-generated method stub
		return userDaoImpl.updateUserBean(user);
	}

	@MyLog(value="用户管理",type=LogEnum.DELETE)
	@Override
	public int deleteUserBean(UserBean user) {
		// TODO Auto-generated method stub
		return userDaoImpl.deleteUserBean(user);
	}

	@MyLog(value="用户管理",type=LogEnum.DELETE)
	@Override
	public int deleteBatchUserBean(int[] ids) {
		// TODO Auto-generated method stub
		return userDaoImpl.deleteBatchUserBean(ids);
	}

	@MyLog(value="用户管理",type=LogEnum.DELETE)
	@Override
	public int deleteUserBean(Integer id) {
		// TODO Auto-generated method stub
		return userDaoImpl.deleteUserBean(id);
	}

	@Override
	public UserBean getUserBeanById(Integer id) {
		// TODO Auto-generated method stub
		return userDaoImpl.getUserBeanById(id);
	}

	@Override
	public Map<String, Object> queryUserBeanById(Integer id) {
		// TODO Auto-generated method stub
		return userDaoImpl.queryUserBeanById(id);
	}

	@Override
	public List<Map<String, Object>> findUserBeanMapByObject(UserBean user) {
		// TODO Auto-generated method stub
		return userDaoImpl.findUserBeanMapByObject(user);
	}

	@Override
	public UserBean findUserBeanByLoginNameAndPwd(String loginName, String pwd) {
		// TODO Auto-generated method stub
		return userDaoImpl.findUserBeanByLoginNameAndPwd(loginName, pwd);
	}

	@Override
	public List<UserBean> findUserBeanByObject(UserBean user) {
		// TODO Auto-generated method stub
		return userDaoImpl.findUserBeanByObject(user);
	}

	@Override
	public List<UserBean> findUserBeanByMap(Map map) {
		// TODO Auto-generated method stub
		return userDaoImpl.findUserBeanByMap(map);
	}

	@Override
	public PageBean findUserBeanList2PageBean(PageBean page, UserBean user) {
		// TODO Auto-generated method stub
		int totalRows = userDaoImpl.countUserBeanList2PageBean(user);
		List<?> datas = null;
		if(totalRows > 0) {
			datas = userDaoImpl.findUserBeanList(page, user);
		}
		page.setTotalRows(totalRows);	
		page.setData(datas);
		return page;
	}

	

}

这个注解是自己写的,如下:

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {

	/**
	 * value 代表着 具体的操作模块
	 * @return
	 */
	String value() default ""; 
	
	/**
	 * 操作类型 0- 新增,1-修改,2-删除
	 * @return
	 */
	LogEnum type();
}

LogEnum枚举也是自己写的,如下:

public enum LogEnum {

	ADD(0),UPDATE(1),DELETE(2);
	
	private int value;
	
	private LogEnum(int value) {
		this.value = value;
	}

	public int getValue() {
		return value;
	}
	
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值