AOP思考

最近在帮一个同事解决AOP异常时,对自己的AOP理解做了一个提纲总结,便于以后回忆。

1. AOP理解

     1)AOP是什么

          AOP,面向切面编程思想。该思想提倡将各组件间具有横切性质的公共逻辑用“切面”封装起来,通过代理以“切入”的方式调用,实现代码的分层、解耦。

     2)AOP解决什么问题
     
          AOP解决的问题是代码逻辑的解耦和分层、公共逻辑的封装和调用问题。

     3)AOP如何解决问题

          首先,按照OOP思想将公共逻辑用对象(切面)封装起来;
          然后,构建业务组件的代理对象,供调用者使用,实现“偷梁换柱”;
          最后,代理根据配置,在调用业务组件前后”智能“的执行切面逻辑;
       
     4)AOP解决问题优势

          业务代码和公共代码在封装和调用方面均实现分层,解耦;
          提高了业务组件的复用度;
          提高了公共逻辑的复用度

     5)AOP与OOP的区别

          从上面看出,AOP是先按照OOP思想来解决问题的,但是传统OOP思想不能解决逻辑分层和解耦问题,于是AOP通过代理手段解决该问题。

          所以,AOP是OOP的补充,AOP=OOP+代理模式。


2. AOP应用

     1)Spring AOP组件

          目标对象:封装了业务逻辑的组件,例如Spring里的普通Service、Dao等Bean;
          代理对象:目标对象的代理,运行时动态生成(JDK动态代理和CGLIB动态代理)
          切面:      封装了公用逻辑的组件,一个切面包含三个元素:通知、切入点、引入;
          通知:      封装了公共逻辑的切面方法(前置、后置、完成、环绕、异常)
          引入:      封装了新增逻辑的组件;
          切入点:   封装了连接点匹配规则的组件,常用的匹配规则有execution/args/within;  
          连接点:   目标对象的方法;

     2)Spring AOP编程

          一个登陆服务组件,其提供login操作;

          在不改变该组件代码的前提下,加强其login操作逻辑、新增注册功能逻辑;


用户信息
package com.sample.domain;

public class User {
	
	private String name;
	private String password;
	
	public User(){}
	
	public User(String name,String password){
		this.name = name;
		this.password = password;
	}

	public String getName() {
		return name;
	}

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

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
	
	public String toString(){
		return "用户名:<"+name+">密码:<"+password+">";
	}
	
}
 
登陆服务组件接口
package com.sample.service;

import com.sample.domain.User;

public interface LoginAndoutService {
	
	
	public String logIn(User user);
	
	public void logOut(User user);
	

}

登陆服务组件实现
package com.sample.service.impl;

import org.springframework.stereotype.Service;

import com.sample.domain.User;
import com.sample.service.LoginAndoutService;

@Service
public class LoginAndoutServiceImpl implements LoginAndoutService {

	@Override
	public String logIn(User user) {
		
		if(null == user)
		throw new RuntimeException("用户不能为空");	
		
		return "用户<"+user.getName()+">登录成功,密码<"+user.getPassword()+">";
	}

	@Override
	public void logOut(User user) {
		
		System.out.println("用户<"+user.getName()+">退出!");
		
	}

}


登陆服务组件切面
package com.sample.aop.aspect;

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

import com.sample.aop.introduction.LogInAndOutStrong;
import com.sample.aop.introduction.impl.LogInAndOutStrongImpl;
import com.sample.domain.User;

@Component
@Aspect
public class LogInAndOutAspect {
	
	
	@DeclareParents(value="com.sample.service.*+",
            defaultImpl=LogInAndOutStrongImpl.class)
	public static LogInAndOutStrong stronger;
	
	
	@Before("com.sample.aop.pointcut.LogInAndOutPoint.logIn_Out_Point() && args(user)")
	public void checkArgs(User user){
		
		if(null == user)
		throw new RuntimeException("用户不能为空!");
		
		System.out.println("开始,检查参数值--->"+user);
		
	}
	
	
	@AfterReturning(pointcut="com.sample.aop.pointcut.LogInAndOutPoint.logIn_Out_Point()",
					returning="rs")
	public void checkResult(String rs){
		
		if( null == rs)
			rs = "方法为void类型,无返回值";
		
		System.out.println("返回,接收返回值--->"+rs);
		
	}
	
	
	@After("com.sample.aop.pointcut.LogInAndOutPoint.logIn_Out_Point()")
	public void finish(){
		
		System.out.println("结束,方法调用完毕--->");
		
	}
	
	
	@AfterThrowing(pointcut="com.sample.aop.pointcut.LogInAndOutPoint.logIn_Out_Point()",
					throwing="ex")
	public void handException(Exception ex){
		
		System.out.println("异常,处理异常--->"+ex);
		
	}
	
	
	@Around("com.sample.aop.pointcut.LogInAndOutPoint.logIn_Out_Point()")
	public Object process(ProceedingJoinPoint pjp) throws Throwable{
		
		System.out.println("环绕,调用方法--->"+pjp.getKind());
		
		return pjp.proceed();
		
	}
	
}


切面引入接口
package com.sample.aop.introduction;

import com.sample.domain.User;

public interface LogInAndOutStrong {
	
	public String regist(User user);

}


切面引入实现
package com.sample.aop.introduction.impl;

import com.sample.aop.introduction.LogInAndOutStrong;
import com.sample.domain.User;

public class LogInAndOutStrongImpl implements LogInAndOutStrong {

	@Override
	public String regist(User user) {
		
		return "用户<"+user.getName()+">注册成功!";
	}

}


切入点定义
package com.sample.aop.pointcut;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;


@Component
@Aspect
public class LogInAndOutPoint {

	@Pointcut("execution (* com.sample.service.impl.LoginAndoutServiceImpl.log*(..))")
	public void logIn_Out_Point(){}
	
}

Spring配置文件
<?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"
	xmlns:task="http://www.springframework.org/schema/task"
	xmlns:tx="http://www.springframework.org/schema/tx" 
	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-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    http://www.springframework.org/schema/task   
    http://www.springframework.org/schema/task/spring-task-3.0.xsd
    http://www.springframework.org/schema/tx  
    http://www.springframework.org/schema/tx/spring-tx.xsd">

	<!-- 启用Spring AOP相关特性 -->
	<aop:aspectj-autoproxy/>
	
	
	<!-- 启用Spring 组件扫描识别特性 -->
	<context:component-scan base-package="com.sample" />
	
</beans>


测试类
package com.sample;

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

import com.sample.aop.introduction.LogInAndOutStrong;
import com.sample.domain.User;
import com.sample.service.LoginAndoutService;

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		User user = new User("张三","123456");
		
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		LoginAndoutService service = (LoginAndoutService)context.getBean("loginAndoutServiceImpl");
		System.out.println(service.logIn(user));
		
		
		LogInAndOutStrong stronger = (LogInAndOutStrong)service;
		System.out.println(stronger.regist(user));
		
	}

}

测试结果
环绕,调用方法--->method-execution
开始,检查参数值--->用户名:<张三>密码:<123456>
返回,接收返回值--->用户<张三>登录成功,密码<123456>
结束,方法调用完毕--->
用户<张三>登录成功,密码<123456>
用户<张三>注册成功!




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值