您的位置:首页 > 编程语言 > Java开发

Spring基础入门AOP

2017-11-19 13:09 405 查看

AOP简介

1.什么是AOP ? 它有什么用?

AOP(Aspect Oriented Programming,面向切面编程), 可以说是OOP(Object Oriented Programing,面向对象编程)的补充和完善。在不改动源码的前提下,对原有的功能进行扩展 | 升级

2.AOP的底层原理是什么?

在JAVA的世界里,能够不改代码而又能进行扩展代码的,不多,常见的有装饰者模式,代理模式(静态代理,动态代理),而AOP的底层使用的是动态代理,因为使用静态代理 | 装饰者模式 需要提供一个实实在在类,而使用动态代理,只需要一个被装饰对象,或对象字节码对象即可

3.代理回顾,静态代理方式



3.代理回顾,动态代理实现方式



画的有点丑,别介意

4.基于JDK方式代码

//创建一个接口   JDK方式需要实现接口,如果类没有实现接口,那么只能使用cglib方式
public interface A {

void run();
void eat();
}


//创建一个实体类   实现接口
public class People implemts A{

public void eat(){
System.out.println("吃");
}
public void run(){
System.out.println("跑");
}
}


public class Jdk {

@Test
public void Test_01(){
A people = new People();  //创建实体类对象

//        使用动态代理
Class clazz = people.getClass();
//Proxy.newProxyInstance()需要的参数
//1.类加载器  2.目标类实现的接口,也就是People实现的接口  3.一个new InvocationHandler()的回调函数

//获取代理对象
A a = (A) Proxy.newProxyInstance(this.getClass().getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//加强睡的方法
if ("eat".equals(method.getName())) {
System.out.println("加餐啦!");
}

return method.invoke(people,args);
}
});

proxy.eat();
}

}


运行结果如下



5.基于Cglib方式代码

主要针对没有实现接口的类,底层通过创建另一个子类作为代理类

//创建一个目标类,不实现接口
public class Anli {

public void eat(){
System.out.println("开始吃");
}

public void run(){
System.out.println("开始跑");
}
}


创建一个测试类

public class Cglib {

@Test
public void Test_01(){
//创建目标类的真实对象,
final Anli anli = new Anli();

//创建一个代理对象
Enhancer enhancer = new Enhancer();  //这不是代理对象,是创建代理对象的模板,可以理解为代理对象工厂

enhancer.setSuperclass(anli.getClass());

enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//加强吃的方法
if ("eat".equals(method.getName())) {
System.out.println("再一次加餐啦");
}

return method.invoke(anli,objects);
}
});

//创建代理类
Anli a = (Anli)enhancer.create();

a.eat();
}
}


运行结果如下



总结 : 被代理类如果实现了接口就使用JDK的方式,如果没有实现,就是用Cglib方式,开发中通常会使用JDK的方式,开发中都是使用接口来定义规范的.

6.回归正题,我们开始讲AOP

讲AOP之前,我们需要了解AOP的术语,

连接点

切入点

切面

话不多说,直接上图



了解完AOP术语,那么我们就开始实际操作

1.导入spring需要的jar包,和日志包(如果没有的话,可以在我上传资源里面下载,注意,jar包只用导入一部分)

导入jar包如下

五个核心jar包

spr
4000
ing-beans-xxx.jar

spring-context-xxx.jar

spring-context.xxx.jar

spring-core-xxx.jar

spring-expression-xxx.jar

日志jar包

jcl-over-slf4j-xxx.jar

log4j-xxx.jar

slf44j-api-xxx.jar

slf4j-log4j-xxx.jar

需要注意的是,导入日志jar包后,需要提供一个log4j.properties文件

导入aop需要的jar包

spring-aop-xxx.jar

spring-aspects-xxx.jar

面向切面过程中Spring AOP是遵循AOP联盟规范实现的,所以需要AOP联盟的接口包

aoplliance-xx.jar

接口包依赖aspectJweaver-xxx.jar

如果没有jar包的话,可以在我的资源里面找

log4j.properties文件内容如下

##\u8BBE\u7F6E\u65E5\u5FD7\u8BB0\u5F55\u5230\u63A7\u5236\u53F0\u7684\u65B9\u5F0F
log4j.appender.s=org.apache.log4j.ConsoleAppender
log4j.appender.s.Target=System.err
log4j.appender.s.layout=org.apache.log4j.PatternLayout
log4j.appender.s.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n

##\u8BBE\u7F6E\u65E5\u5FD7\u8BB0\u5F55\u5230\u6587\u4EF6\u7684\u65B9\u5F0F
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n

##\u65E5\u5FD7\u8F93\u51FA\u7684\u7EA7\u522B\uFF0C\u4EE5\u53CA\u914D\u7F6E\u8BB0\u5F55\u65B9\u6848
log4j.rootLogger=info, s, file


2.导入applicationContext.xml配置所需要的约束 (aop约束)

spring-framework-4.2.9.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html里面搜索aop就行

spring-framework-4.2.9.RELEASE是在spring官网下载的文件夹名

html索搜快捷键 ctrl+shift +f

复制约束,粘贴到xml即可

3.编写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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

<bean id="Pipixia" class="cn.itcast.aop.Pipixia"/>
<bean id="People" class="cn.itcast.aop.People"/>

<aop:config >

<!-- 切入点  到底哪些方法要被扩展
execution(* com.xyz.myapp.service..(..))
execution: 固定写法
第一个* : 任意返回值
com.xyz.myapp.service : 具体包
第二个* : 包下的所有类
第三个* : 类中的所有方法
(..) : 方法的任意参数
-->
<!--创建一个切入点-->
<aop:pointcut id="point" expression="execution(* cn.itcast.aop.Pipixia.*(..))"/>

<!--创建一个切面  ,ref是提供扩展方法的类-->
<aop:aspect ref="People">
<!--提供People类的eat方法,before是增强位置-->
<aop:before method="eat" pointcut-ref="point" />
</aop:aspect>
</aop:config>
</beans>


AOP增加介绍

<aop:config>
<!-- us  === saveUser
ps  === saveProduct
os  ===saveOrder -->
<aop:pointcut expression="execution(* com.itcast.*.*.eat*(..))" id="aa"/>

<aop:aspect ref="People">

<!-- 前置增强,People类eat方法会在执行itcast包下所有类的方法前执行,只要是itcast包下的方法,执行前都会执行一遍People的方法,出异常不知晓 -->
<!-- <aop:before method="eat" pointcut-ref="aa" /> -->

<!-- 最终增强  不管有没有异常都执行-->
<!-- <aop:after method="eat" pointcut-ref="aa" /> -->

<!-- 环绕增强 -->
<!-- <aop:before method="eat" pointcut-ref="aa" />
<aop:after method="eat" pointcut-ref="aa" /> -->
<!--环绕增强,被增强方法执行前后都是执行eat方法,不过需要额外配置-->
<!-- <aop:around method="around" pointcut-ref="aa"/> -->

<!-- 后置增强,被增强方法执行完后会执行一遍 People类的eat方法-->
<!-- <aop:after-returning method="eat" pointcut-ref="aa"/> -->

<!-- 异常增强,被增强方法出了异常才会增强执行eat方法 -->
<aop:after-throwing method="eat" pointcut-ref="aa"/>
</aop:aspect>
</aop:config>


由于时间问题,就不演示了

就值演示一个before前置增强

编写一个测试类

//使用spring提供的测试方法,使用需要导入test的jar包
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo_02 {

@Resource
private Pipixia p;

@Test
public  void demo_01(){

p.eat();

}
}


执行结果如下



它先执行了People的eat方法,



然后再执行了Pipixia的eat方法



以上就是AOP简单入门,下次我们会讲IOC,DI注解写法,有问题评论留言

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息