Spring笔记
前言
Spring学习笔记
一、AOP概念
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程(也叫面向方面),可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。
AOP是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP是OOP的延续,主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。
在Spring中提供了AOP的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
二、简单例子(简单计算器)
1.普通写法
代码如下:
(1)接口:
public interface Cal {
public int add(int num1,int num2);
public int sub(int num1,int num2);
public int mul(int num1,int num2);
public int div(int num1,int num2);
}
(2)实现类:
public class Calimpl implements Cal {
@Override
public int add(int num1, int num2) {
System.out.println("add方法的参数为:"+num1+","+num2);
int result=num1+num2;
System.out.println("add方法结果为:"+result);
return result;
}
@Override
public int sub(int num1, int num2) {
System.out.println("sub方法的参数为:"+num1+","+num2);
int result=num1-num2;
System.out.println("sub方法结果为:"+result);
return result;
}
@Override
public int mul(int num1, int num2) {
System.out.println("mul方法的参数为:"+num1+","+num2);
int result=num1*num2;
System.out.println("mul方法结果为:"+result);
return result;
}
@Override
public int div(int num1, int num2) {
System.out.println("div方法的参数为:"+num1+","+num2);
int result=num1/num2;
System.out.println("div方法结果为:"+result);
return result;
}
}
(3)测试:
public static void main(String[] args) {
Cal cal=new Calimpl();
System.out.println(cal.add(2,3));
System.out.println(cal.sub(2,3));
System.out.println(cal.mul(2,3));
System.out.println(cal.div(2,3));
}
(4)结果
这种普通写法耦合度高,不易于后期代码维护与管理
2.AOP底层原理实现
代码如下:
(1)在1的基础是对实现类进行改写:
public class Calimpl implements Cal {
@Override
public int add(int num1, int num2) {
return num1+num2;
}
@Override
public int sub(int num1, int num2) {
return num1-num2;
}
@Override
public int mul(int num1, int num2) {
return num1*num2;
}
@Override
public int div(int num1, int num2) {
return num1/num2;
}
}
(2)创建MyInvocationHandler类,实现InvocationHandler接口,生成动态代理类
public class MyInvocationHandler implements InvocationHandler {
//委托对象
private Object object;
//返回代理对象
public Object bind(Object object){
this.object=object;
return Proxy.newProxyInstance(
object.getClass().getClassLoader(),//获取类加载器
object.getClass().getInterfaces(),//获取委托类的接口信息(因为代理类必须具备委托类的所有功能)
this);//传入一个InvocationHandler实例(this代表当前MyInvocationHandler实例)
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//实现业务代码和非业务代码的解耦合
System.out.println(method.getName()+"方法参数是"+ Arrays.toString(args));
Object result = method.invoke(this.object,args);
System.out.println(method.getName()+"结果是:"+result);
return result;
}
}
(3)测试
public static void main(String[] args) {
//实例化委托对象
Cal cal=new Calimpl();
//获取代理对象
MyInvocationHandler myInvocationHandler =new MyInvocationHandler();
Cal proxy=(Cal) myInvocationHandler.bind(cal);
proxy.add(1,5);
proxy.sub(4,5);
proxy.mul(2,3);
proxy.div(4,1);
}
(4)结果
3.Spring AOP实现
(1)导入AOP相关依赖
<!-- Spring AOP -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.22</version>
</dependency>
<!--AspectJ支持-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.bundles</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8_2</version>
</dependency>
(2)编写xml文件,实现自动扫包和为委托对象自动生成代理对象
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 自动扫包 -->
<context:component-scan base-package="AOP"></context:component-scan>
<!-- 为委托对象自动生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
(3)添加@Component注解,将委托类注入IoC容器
@Component
public class Calimpl implements Cal {
@Override
public int add(int num1, int num2) {
return num1+num2;
}
@Override
public int sub(int num1, int num2) {
return num1-num2;
}
@Override
public int mul(int num1, int num2) {
return num1*num2;
}
@Override
public int div(int num1, int num2) {
return num1/num2;
}
}
(3)创建切面类并添加注解
@Component
@Aspect
public class LoggerAspect {
/**在执行业务方法之前执行**/
@Before("execution(public int AOP.Cal.impl.Calimpl.*(..))")
public void before(JoinPoint joinPoint){
String name=joinPoint.getSignature().getName();
String args= Arrays.toString(joinPoint.getArgs());
System.out.println(name+"方法的参数是:"+args);
}
/**在执行业务方法之后执行**/
@After("execution(public int AOP.Cal.impl.Calimpl.*(..))")
public void after(JoinPoint joinPoint){
String name=joinPoint.getSignature().getName();
System.out.println(name+"方法执行完毕");
}
/**表示方法的执行时机是在业务方法返回结果之后,
* execution表达式表示切入点是Calimpl类中的具体方法,
returning是将业务方法的返回值与切面类方法的形参进行绑定**/
@AfterReturning(value = "execution(public int AOP.Cal.impl.Calimpl.*(..))",returning = "result")
public void afterReturn(JoinPoint joinPoint,Object result){
String name=joinPoint.getSignature().getName();
System.out.println(name+"方法的结果是:"+result);
}
/**表示方法的执行时机是在业务方法抛出异常之后,
* execution表达式表示切入点是Calimpl类中的具体方法,
returning是将业务方法的异常与切面类方法的形参进行绑定**/
@AfterThrowing(value = "execution(public int AOP.Cal.impl.Calimpl.*(..))",throwing = "ex")
public void afterThrowing(JoinPoint joinPoint,Exception ex){
String name=joinPoint.getSignature().getName();
System.out.println(name+"方法抛出异常"+ex);
}
}
(4)测试
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring-aop.xml");
Cal cal=(Cal) applicationContext.getBean("calimpl");
System.out.println(cal.add(10,3));
System.out.println(cal.sub(10,3));
System.out.println(cal.div(10,1));
System.out.println(cal.mul(10,3));
}
(5)结果
(6)总结