一些介绍:
1.面向方面编程是希望能够将通用需求功能从不相关的类当中分离出来,能够使得很多类共享一个行为,一旦发生变化,不必修改很多类,而只需要修改这个行为即 可 、
2.应用:
AOP 主要应用于日志记录,性能统计,安全控制 , 事务处理等方面。
在spring中配置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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:aspectj-autoproxy /> <!– 支持AOP的注解方式-->
</beans>
Annotation 方式配置 AOP
package com.yang.interceptor;
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.Pointcut;
import org.springframework.stereotype.Component;
import com.yang.bean.User;
/**
* 日志拦截器
*/
@Aspect
@Component
public class TestInterceptor {
@Pointcut("execution(public * com.yang.test.*.test*(..))") //声明一个名字为log的切入点
public void log(){
}
@Before("log()"+"&&args(user)") //使用pointcut-->log .前置通知.处理传入的参数跟下面的形参保持一致即可。
public void before(User user){
System.out.println("方法执行前:"+user.getUname());
user.setUname("lisi");
System.out.println("方法执行前!");
}
@After("log()") //最终后置通知。不管有无异常,最终都会执行!
public void after(){
System.out.println("方法执行后!");
}
@AfterReturning("log()") //方法正常结束,后置通知
public void afterReturning(){
System.out.println("方法执行后!after returning!");
}
@AfterThrowing("log()") //抛出异常会执行,异常通知
public void afterThrowing(){
System.out.println("方法执行后!after throwing!");
}
@Around("log()") //环绕通知在一个方法执行之前和之后执行
public Object around(ProceedingJoinPoint pjp){
System.out.println("环绕通知,方法执行前!");
Object obj = null;
try {
obj = pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕通知,方法执行后!");
return obj;
}
}
package com.yang.test;
import org.springframework.stereotype.Component;
import com.yang.bean.User;
@Component("userDao")
public class UserDao {
public void test1(User user){
System.out.println(user.getUname());
System.out.println("UserDao.test1()");
}
public void test2(){
System.out.println("UserDao.test2()");
}
public void aaa(){
System.out.println("UserDao.aaa()");
}
}
package com.yang.bean;
public class User {
private int id;
private String uname;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
}
package com.yang.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.yang.bean.User;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});
UserDao us = (UserDao) context.getBean("userDao");
User u = new User();
u.setUname("zhangsan");
us.test1(u);
us.test2();
us.aaa();
}
}
个人的理解:
TestInterceptor中的方法中对应的注解最后是根据反射拿到的。
@Pointcut("execution(public * com.yang.test.*.test*(..))") //声明一个名字为log的切入点
Pointcut中的注解是使用正则进行解析的,当然中间也有一些替换。
xml中配置xop
<?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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
">
<aop:aspectj-autoproxy /> <!-- 支持注解方式 -->
<context:component-scan base-package="com.yang"/>
<!-- 采用配置方式使用AOP -->
<bean id="logInterceptor" class="com.yang.spring.aop.LogInterceptor"></bean>
<aop:config >
<!--定义切点 名字log -->
<aop:pointcut expression="execution(public !java.lang.String com.yang.spring.aop.UserDaoImpl.*(com.bjsxt.spring.aop.User,..))" id="log"/>
<!-- 定义切面 logAspect-->
<aop:aspect id="logAspect" ref="logInterceptor">
<!-- 定义前置通知 -->
<!-- arg-names="user,age,name,test" 多参数 arg-names 指定before参数名 -->
<aop:before method="before" arg-names="user" pointcut="execution(!java.lang.String com.yang.spring.aop.UserDaoImpl.add(..)) and args(user)" />
<!-- 后置通知 -->
<aop:after method="after" pointcut-ref="log" />
<aop:after-throwing method="afterThrowing" pointcut-ref="log"/>
<aop:after-returning method="afterReturning" pointcut-ref="log"/>
<aop:around method="around" pointcut-ref="log"/>
</aop:aspect>
</aop:config>
</beans>
arg-names是为了显式地定义before方法中对应的参数的名字。
pointcut="execution(!java.lang.String com.yang.spring.aop.UserDaoImpl.add(..)) and args(user)" />
我的理解就是相当于查add方法,参数个数为1个,类型为user,(必须要有对应的User类,before中的before方法必须是
before(User user)类型的)