1.要明白几个知识点
代理模式
|---动态代理
|--静态代理
2.aop(面向切面编程)是oop(面向对象)的补充。
aop也可以分为静态aop(如aspectj就是静态aop)和动态aop(spring aop用的就是动态aop)
其中,动态aop使用的是JDK动态代理或者cglib代理(两者有什么区别?)
3.为什么需要aop
4 aspectj实例
首先要下载aspectj.jar,然后java -jar 运行该jar包,然后配置相关环境变量,然后就可以了
先定义两个业务逻辑类
/*
业务逻辑类Hello
*/
package com.service;
public class Hello
{
//业务逻辑方法
public void foo(){
System.out.println("执行Hello组件的foo方法");
}
public int addUser(String name){
System.out.println("执行Hello组件的addUser方法,添加用户:"+name);
return 1;
}
}
/*
业务逻辑组件World,每个函数完成不同的业务逻辑功能
*/
package com.service;
public class World
{
public void bar(){
System.out.println("执行World组件的bar方法");
}
}
然后定义一个切面类,一个很特别的类,注意看细节
/*
切片类,该类相当于一个刀子,可以切入到业务逻辑类中
*/
package com.aspect;
public aspect AuthAspect
{
//第一个星号表示返回值不限,第二个任意类,第三个任意方法,..表示任意个参数和类型
before():execution(* com.service.*.*(..) )
{
System.out.println("业务逻辑执行之前进行权限检查");
}
}
然后是测试类
package com.test;
import com.service.*;
public class AspectTest
{
public static void main(String []args){
Hello hello=new Hello();
World world=new World();
//---
hello.foo();
hello.addUser("tom");
//---
world.bar();
}
}
把上面几个类使用ajc -d . xxx.java编译好,ajc是aspectj.jar中的命令,理解为加强版的javac
编译过程中会使用动态代理自动为业务逻辑类增加相应的代码,可以用反编译工具查看编译后的.class文件
然后运行test类 java com.test.AspectTest 会看到如下结果:
>业务逻辑执行之前进行权限检查
>执行Hello组件的foo方法
>业务逻辑执行之前进行权限检查
>执行Hello组件的addUser方法,添加用户:tom
>执行World组件的bar方法
--实在是很神奇
---------------------------------------------------------------------
接下来是spring 的aop,首先要搭建环境
选择构建maven项目,下面是依赖(也是spring的基本依赖)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<!-- 添加spring-tx包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<!-- spring 依赖包 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.5</version>
</dependency>
spring.xml配置文件,注意scema要添加aop相关的
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean id="firstAspect" class="com.aop.aspect.FourAdviceAspect"></bean>
<bean id="secondAspect" class="com.aop.aspect.SecondAspect"></bean>
<bean id="userService" class="com.service.UserService"></bean>
<aop:config>
<aop:aspect id="firstAspect" ref="firstAspect" order="2">
<aop:after pointcut="execution(* com.service.*.*(..))" method="release"></aop:after>
<aop:before pointcut="execution(* com.service.*.*(..))" method="authority"></aop:before>
<aop:after-returning pointcut="execution(* com.service.*.*(..))" returning="rvt" method="log"></aop:after-returning>
<aop:around pointcut="execution(* com.service.*.*(..))" method="processTx"></aop:around>
</aop:aspect>
<aop:aspect id="secondAspect" ref="secondAspect">
<aop:before pointcut="execution(* com.service.*.*(..)) and args(aa)" method="authority"></aop:before>
</aop:aspect>
</aop:config>
</beans>
两个切面类
package com.aop.aspect;
/*
* 另一个切面类
*
* */
public class SecondAspect {
//before
public void authority(String aa){
System.out.println("secondAspect before增强");
System.out.println("目标方法的参数为"+aa);
}
}
package com.aop.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
/*
* 一个普通的类,作为切面类
* 类中的每个方法监听一个切入点
* */
public class FourAdviceAspect {
//是around、before、after取决于函数中参数的类型
//用于around
public Object processTx(ProceedingJoinPoint jp) throws Throwable{
System.out.println("around增强,执行目标方法之前,执行一些事务...");
//获取目标方法的参数
Object []args=jp.getArgs();
if(args!=null&&args.length>0&&args[0].getClass()==String.class){
args[0]="EQ专属参数 "+args[0];
}
//执行目标方法,并获取返回值
Object rvt=jp.proceed(args);
if(rvt==null){
rvt="null";
}
System.out.println("1)目标方法的返回值是:"+rvt.toString());
System.out.println("1)执行目标方法之后,执行一些事务...");
return rvt;
}
//before ,
public void authority(JoinPoint jp){
System.out.println("2)before增强,模拟身份权限验证");
System.out.println("2)before增强,被植入增强处目标的方法为:"+jp.getSignature().getName());
System.out.println("2)before增强,目标方法的参数为"+jp.getArgs());
System.out.println("2)before增强,被植入增强处目标对象为"+jp.getTarget());
}
//after returning
public void log(JoinPoint jp,Object rvt){//rvt为目标方法的返回值
System.out.println("3)after returning增强处理,获取目标方法返回值"+rvt);
System.out.println("3)after returning增强处理,模拟日志记录功能");
System.out.println("3)after returning增强处理,被植入增强处理的目标方法为:"+jp.getSignature().getName());
System.out.println("3)after returning增强,目标方法的参数为"+jp.getArgs());
System.out.println("3)after returning增强,被植入增强处目标对象为"+jp.getTarget());
}
//after
public void release(JoinPoint jp){
System.out.println("4)after增强,模拟释放资源...");
System.out.println("4)after增强,被植入增强处目标的方法为:"+jp.getSignature().getName());
System.out.println("4)after增强,目标方法的参数为"+jp.getArgs());
System.out.println("4)after增强,被植入增强处目标对象为"+jp.getTarget());
}
}
一个测试类
package com.eqtest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.service.UserService;
public class AopTest {
public static void main(String[] args) {
//UserService us=new UserService();
ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
UserService us=ctx.getBean("userService",UserService.class);
us.addUser("tom");
us.queryUser(522);
}
}
项目的目录结构如下:
运行结果:
五月 08, 2016 9:33:48 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6293068a: startup date [Sun May 08 21:33:48 CST 2016]; root of context hierarchy
五月 08, 2016 9:33:49 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring.xml]
2)before增强,模拟身份权限验证
2)before增强,被植入增强处目标的方法为:addUser
2)before增强,目标方法的参数为[Ljava.lang.Object;@160ee454
2)before增强,被植入增强处目标对象为com.service.UserService@2bb0521c
around增强,执行目标方法之前,执行一些事务...
secondAspect before增强
目标方法的参数为EQ专属参数 tom
增加新的user
1)目标方法的返回值是:null
1)执行目标方法之后,执行一些事务...
3)after returning增强处理,获取目标方法返回值null
3)after returning增强处理,模拟日志记录功能
3)after returning增强处理,被植入增强处理的目标方法为:addUser
3)after returning增强,目标方法的参数为[Ljava.lang.Object;@160ee454
3)after returning增强,被植入增强处目标对象为com.service.UserService@2bb0521c
4)after增强,模拟释放资源...
4)after增强,被植入增强处目标的方法为:addUser
4)after增强,目标方法的参数为[Ljava.lang.Object;@160ee454
4)after增强,被植入增强处目标对象为com.service.UserService@2bb0521c
2)before增强,模拟身份权限验证
2)before增强,被植入增强处目标的方法为:queryUser
2)before增强,目标方法的参数为[Ljava.lang.Object;@747a1b5b
2)before增强,被植入增强处目标对象为com.service.UserService@2bb0521c
around增强,执行目标方法之前,执行一些事务...
查询用户
1)目标方法的返回值是:0000000
1)执行目标方法之后,执行一些事务...
3)after returning增强处理,获取目标方法返回值0000000
3)after returning增强处理,模拟日志记录功能
3)after returning增强处理,被植入增强处理的目标方法为:queryUser
3)after returning增强,目标方法的参数为[Ljava.lang.Object;@747a1b5b
3)after returning增强,被植入增强处目标对象为com.service.UserService@2bb0521c
4)after增强,模拟释放资源...
4)after增强,被植入增强处目标的方法为:queryUser
4)after增强,目标方法的参数为[Ljava.lang.Object;@747a1b5b
4)after增强,被植入增强处目标对象为com.service.UserService@2bb0521c