AOP面向切面编程:
将散落在系统中的公共功能代码进行集中式的管理和配置
解耦、可扩展性、可维护性的基础上
切面(要加入的新对象) 切入点(那些方法前或者后添加新功能,方法) 织入(动态代理原理) 连接点(JoinPoint)
不改变原有代码,添加新的代码
动态代理原理
范例:使用AOP的思想实现用户的添加:
实体类
package com.oupeng.pojo;
public class User {
private Integer id;
private String userName;
private String password;
private String email;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
1.编写数据访问层
- 1.1 数据访问接口
package com.oupeng.dao;
import com.oupeng.pojo.User;
public interface UserDao {
//定义用户保存的方法
public int save(User user);
}
- 1.2 数据访问实现类
package com.oupeng.dao.impl;
import com.oupeng.dao.UserDao;
import com.oupeng.pojo.User;
public class UserDaoImpl implements UserDao{
@Override
public int save(User user) {
System.out.println("保存用户到数据库成功");
return 1;
}
}
2.编写业务逻辑层
- 2.1 业务逻辑层接口
package com.oupeng.service;
import com.oupeng.pojo.User;
public interface UserService {
//定义添加用户
public int addNewUser(User user);
}
- 2.2 业务逻辑层实现类
package com.oupeng.service.impl;
import com.oupeng.dao.UserDao;
import com.oupeng.pojo.User;
import com.oupeng.service.UserService;
public class UserServiceImpl implements UserService {
//注入数据访问层
/**
* 之前:UserDaoImpl ud=new UserDaoImpl();
* ud.save(user);
*/
//Spring
UserDao ud;
public UserDao getUd() {
return ud;
}
public void setUd(UserDao ud) {
this.ud = ud;
}
@Override
public int addNewUser(User user) {
ud.save(user);
return 2;
}
}
3 配置spring配置文件
<!-- 配置数据访问层bean -->
<bean id="userdao" class="com.oupeng.dao.impl.UserDaoImpl"/>
<!-- 配置业务逻辑层bean -->
<bean id="userService" class="com.oupeng.service.impl.UserServiceImpl">
<property name="ud" ref="userdao"></property>
</bean>
4.测试类
package com.oupeng.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.oupeng.pojo.User;
import com.oupeng.printer.Printer;
import com.oupeng.service.UserService;
public class TestPrinter {
@Test
public void testPrinter() {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService ud=(UserService) context.getBean("userService");
User user=new User();
user.setUserName("曹操");
user.setPassword("565566");
user.setEmail("256@163.com");
user.setId(001);
ud.addNewUser(user);
}
}
执行结果
保存用户到数据库成功.....
现在在不改原码的情况下,增加新功能
1、实现日志打印
增加AOP用于处理增强的类(定义方法)
package com.oupeng.logger;
import java.util.Arrays;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
public class UserServiceLogger {
private static final Logger log=Logger.getLogger(UserServiceLogger.class);
//定义用于前置增强处理的方法 JoinPoint连接点可以调用获取方法的名称参数
public void beforePrintLogger(JoinPoint jp) {
log.info("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法,方法参数"+Arrays.toString(jp.getArgs()));
}
//定义用于后置增强处理的方法
public void afterReturningPrintLogger(JoinPoint jp,Object result){
log.info("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法,方法返回值:"+result);
}
}
配置文件
<!-- 配置用于增强处理的Bean组件 -->
<bean id="userservicelogger"
class="com.oupeng.logger.UserServiceLogger"></bean>
<!-- 开始进行AOP配置 -->
<aop:config>
<!-- 先配置切入点 -->
<!-- 运行public int addNewUser(com.oupeng.pojo.User)这个方法时增强处理 -->
<!-- execution(public * addNewUser(..) -->
<aop:pointcut
expression="execution(public int addNewUser(com.oupeng.pojo.User))"
id="pointcut" />
<!-- 切面配置 -->
<aop:aspect ref="userservicelogger">
<!-- 前置增强 -->
<aop:before method="beforePrintLogger"
pointcut-ref="pointcut" />
<!-- 后置增强 -->
<aop:after-returning
method="afterReturningPrintLogger" pointcut-ref="pointcut"
returning="result" />
</aop:aspect>
</aop:config>
测试
package com.oupeng.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.oupeng.pojo.User;
import com.oupeng.service.UserService;
public class TestService {
@Test
public void testService() {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService ud=(UserService) context.getBean("userService");
User user=new User();
user.setUserName("曹操");
user.setPassword("565566");
user.setEmail("256@163.com");
user.setId(001);
ud.addNewUser(user);
}
}
执行结果
07-15 01:04:16[INFO]org.springframework.context.support.ClassPathXmlApplicationContext
-Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@769c9116: startup date [Wed Jul 15 01:04:16 CST 2020]; root of context hierarchy
07-15 01:04:16[INFO]org.springframework.beans.factory.xml.XmlBeanDefinitionReader
-Loading XML bean definitions from class path resource [applicationContext.xml]
07-15 01:04:16[INFO]org.springframework.beans.factory.support.DefaultListableBeanFactory
-Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@d44fc21: defining beans [HelloSpring,A4,B5,color,gray,printer,userdao,userService,userservicelogger,org.springframework.aop.config.internalAutoProxyCreator,pointcut,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0,org.springframework.aop.aspectj.AspectJPointcutAdvisor#1]; root of factory hierarchy
07-15 01:04:17[INFO]com.oupeng.logger.UserServiceLogger
-调用com.oupeng.service.impl.UserServiceImpl@3d74bf60的addNewUser方法,方法参数[com.oupeng.pojo.User@27ce24aa]
保存用户到数据库成功.....
07-15 01:04:17[INFO]com.oupeng.logger.UserServiceLogger
-调用com.oupeng.service.impl.UserServiceImpl@3d74bf60的addNewUser方法,方法返回值:2
public * addNewUser(com.oupeng.pojo.User): “*”表示匹配所有类型的返回值。
public void *(com.oupeng.pojo.User): “*”表示匹配所有方法名。
public void addNewUser(..): “..”表示匹配所有参数个数和类型。
* com.service.*.*(..):匹配com.service包下所有类的所有方法。
* com.service..*.*(..):匹配com.service包及其子包下所有类的所有方法
增强处理:前置增强、后置增强、 异常处理增强 、环绕增强、最终增强
异常处理增强:
当程序发生异常的时候,程序员想介入程序执行,完善程序功能,往往用于程序调试
1.编写异常处理增强类 ErrorLogger
package com.oupeng.aop;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
public class ErrorLogger {
private Logger log=Logger.getLogger(ErrorLogger.class);
//定义增强方法
public void afterThrowing(JoinPoint jp,RuntimeException e){
log.error(jp.getSignature().getName()+"方法发生了异常"+e.getMessage());
}
}
2.配置异常处理增强
先配置增强处理Bean
aop配置
配置切入点
切入面
配置异常处理增强
<!-- 配置异常处理增强Bean -->
<bean id="errorLogger" class="com.oupeng.aop.ErrorLogger" />
<!-- aop配置 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* com.oupeng.service.UserService.*(..))"
id="pointcut1" />
<!-- 配置切面 -->
<aop:aspect ref="errorLogger">
<!-- 异常处理增强 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut1" throwing="e" />
</aop:aspect>
</aop:config>
3.目标方法,手动抛出异常
package com.oupeng.service.impl;
import com.oupeng.dao.UserDao;
import com.oupeng.pojo.User;
import com.oupeng.service.UserService;
public class UserServiceImpl implements UserService {
//注入数据访问层
/**
* 之前:UserDaoImpl ud=new UserDaoImpl();
* ud.save(user);
*/
//Spring
UserDao ud;
String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
//默认构造方法
public UserServiceImpl(){
System.out.println("业务逻辑类的默认构造方法");
}
//带参数构造方法
public UserServiceImpl(UserDao _ud,String _str){
this.ud=_ud;
this.str=_str;
}
public UserDao getUd() {
return ud;
}
public void setUd(UserDao ud) {
this.ud = ud;
}
public void addNewUser(User user) {
ud.save(user);
System.out.println(this.str);
throw new RuntimeException("对不起,程序发生了运行时异常,请联系管理员...");
}
}
4.编写测试 程序
@Test
public void testException(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService ud=(UserService)context.getBean("userService");
User user=(User)context.getBean("user");
ud.addNewUser(user);
}
执行结果
业务逻辑类的默认构造方法
07-15 20:37:30[INFO]com.oupeng.logger.UserServiceLogger
-调用com.oupeng.service.impl.UserServiceImpl@694abbdc的addNewUser方法,方法参数[com.oupeng.pojo.User@4466af20]
保存用户到数据库成功.....
保存用户到数据库成功....
1
张飞
123456
zhangfei@sanguo.com
哈哈
07-15 20:37:30[ERROR]com.oupeng.aop.ErrorLogger
-addNewUser方法发生了异常对不起,程序发生了运行时异常,请联系管理员...
环绕增强:
在目标方法执行之前和之后共同完善程序现有的功能,以便增强程序功能或者修复Bug
- 编写环绕增强处理类
package com.oupeng.aop;
import java.util.Arrays;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
public class ArroundLogger {
private Logger log=Logger.getLogger(ArroundLogger.class);
//定义环绕增强方法
public Object arroundLogger(ProceedingJoinPoint jp){
log.info("调用环绕增强开始了..."+jp.getSignature().getName()+"方法被调用,方法参数:"+Arrays.toString(jp.getArgs()));
Object object=null;
try {
//目标方法执行
object=jp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
log.info("调用环绕增强结束了..."+jp.getSignature().getName()+"方法被调用,方法返回值:"+object);
return object;
}
}
- 配置环绕增强处理类Bean组件
先配置增强处理Bean
aop配置
配置切入点
切入面
配置环绕增强
<!-- 配置环绕增强Bean -->
<bean id="arroundBean" class="com.oupeng.aop.ArroundLogger" />
<!-- aop配置 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* com.oupeng.service.UserService.*(..))"
id="pointcut2" />
<!-- 配置切面 -->
<aop:aspect ref="arroundBean">
<!-- 环绕增强 -->
<aop:around method="arroundLogger" pointcut-ref="pointcut2" />
</aop:aspect>
</aop:config>
3.编写测试程序:
@Test
public void testArroundLogger(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService ud=(UserService)context.getBean("userService");
User user=(User)context.getBean("user");
ud.addNewUser(user);
}
执行结果
07-15 21:14:16[INFO]org.springframework.context.support.ClassPathXmlApplicationContext
-Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@769c9116: startup date [Wed Jul 15 21:14:16 CST 2020]; root of context hierarchy
07-15 21:14:16[INFO]org.springframework.beans.factory.xml.XmlBeanDefinitionReader
-Loading XML bean definitions from class path resource [applicationContext.xml]
07-15 21:14:16[INFO]org.springframework.beans.factory.support.DefaultListableBeanFactory
-Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1786dec2: defining beans [userdao,userService,user,testentity,userservicelogger,org.springframework.aop.config.internalAutoProxyCreator,pointcut,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0,org.springframework.aop.aspectj.AspectJPointcutAdvisor#1,errorLogger,pointcut1,org.springframework.aop.aspectj.AspectJPointcutAdvisor#2,arroundBean,pointcut2,org.springframework.aop.aspectj.AspectJPointcutAdvisor#3]; root of factory hierarchy
业务逻辑类的默认构造方法
07-15 21:14:16[INFO]com.oupeng.logger.UserServiceLogger
-调用com.oupeng.service.impl.UserServiceImpl@7b9a4292的addNewUser方法,方法参数[com.oupeng.pojo.User@59309333]
07-15 21:14:16[INFO]com.oupeng.aop.ArroundLogger
-调用环绕增强开始了...addNewUser方法被调用,方法参数:[com.oupeng.pojo.User@59309333]
保存用户到数据库成功.....
保存用户到数据库成功....
1
张飞
123456
zhangfei@sanguo.com
哈哈
07-15 21:14:16[INFO]com.oupeng.aop.ArroundLogger
-调用环绕增强结束了...addNewUser方法被调用,方法返回值:null
07-15 21:14:16[INFO]com.oupeng.logger.UserServiceLogger
-调用com.oupeng.service.impl.UserServiceImpl@7b9a4292的addNewUser方法,方法返回值:null
最终增强:
确保增强处理时一定要执行的业务代码就可以用最终增强处理增强
1.编写最终增强处理类
package com.oupeng.aop;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
public class AfterLogger {
private Logger log=Logger.getLogger(AfterLogger.class);
//定义最终增强方法
public void afterLogger(JoinPoint jp){
System.out.println("出纳开始准备数据....");
System.out.println("开始打印每周财务报表........");
System.out.println("开始打印每月的财务报表.....");
}
}
2.配置最终增强处理类组件
配置增强处理Bena组件
aop配置
配置切入点
切入面
配置最终增强
<!-- 配置最终增强Bean -->
<bean id="finalBean" class="com.oupeng.aop.AfterLogger" />
<!-- aop配置 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* com.oupeng.service.UserService.*(..))"
id="pointcut3" />
<!-- 配置切面 -->
<aop:aspect ref="finalBean">
<!-- 最终增强 -->
<aop:after method="afterLogger" pointcut-ref="pointcut3" />
</aop:aspect>
</aop:config>
3.编写测试程序:
@Test
public void testArroundLogger(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService ud=(UserService)context.getBean("userService");
User user=(User)context.getBean("user");
ud.addNewUser(user);
}
执行结果
开始打印每周财务报表........
开始打印每月的财务报表.....
07-15 21:20:38[INFO]com.oupeng.aop.ArroundLogger
-调用环绕增强结束了...addNewUser方法被调用,方法返回值:null
07-15 21:20:38[INFO]com.oupeng.logger.UserServiceLogger
-调用com.oupeng.service.impl.UserServiceImpl@6d763516的addNewUser方法,方法返回值:null