基于代理的AOP
1)jar包
通常有cglib.jar足够了
2)接口
StudentDao .java
package com.dao;
public interface StudentDao {
public abstract void saveStudent();
public abstract void queryStudent();
}
3)接口的实现
StudentDaoImpl .java
package com.dao.impl;
import com.dao.StudentDao;
public class StudentDaoImpl implements StudentDao{
@Override
public void saveStudent() {
System.out.println("正在保存");
}
@Override
public void queryStudent() {
System.out.println("正在查询");
}
}
4)代理类
StudentDaoProxy .java
package com.proxy;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
public class StudentDaoProxy implements MethodBeforeAdvice,AfterReturningAdvice{
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
System.out.println("after");
}
@Override
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
System.out.println("before");
}
}
5)xml配置
applicationContext.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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--定义实现类bean -->
<bean id="studentDaoImpl" class="com.dao.impl.StudentDaoImpl"/>
<!--定义代理类的bean -->
<bean id="studentDaoProxy" class="com.proxy.StudentDaoProxy"></bean>
<!--定义切入点 -->
<bean id="studentDaoImplPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value=".*Student"></property>
</bean>
<!--定义通知 -->
<bean id="studentDaoAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="studentDaoProxy"/>
<property name="pointcut" ref="studentDaoImplPointcut"/>
</bean>
<!--定义代理工厂 -->
<bean id="studentProxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="studentDaoImpl"/>
<property name="interceptorNames" value="studentDaoAdvisor"/>
<property name="proxyInterfaces" value="com.dao.StudentDao"/>
</bean>
</beans>
6)测试类
package com.proxy;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.dao.StudentDao;
import com.dao.impl.StudentDaoImpl;
import junit.framework.TestCase;
public class Test extends TestCase{
public void ProxyTest(){
ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext.xml");
StudentDao studentDao=new StudentDaoImpl();
studentDao=(StudentDao) ctx.getBean("studentProxyFactory");
studentDao.saveStudent();
studentDao.queryStudent();
}
}
自动代理的AOP
不在需要定义代理工厂
1)基于代理的AOP的 2)、3)、4)
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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--定义实现类bean -->
<bean id="studentDaoImpl" class="com.dao.impl.StudentDaoImpl"/>
<!--定义代理类的bean -->
<bean id="studentDaoProxy" class="com.proxy.StudentDaoProxy"></bean>
<!--定义支持正则表达式的通知 -->
<bean id="studentDaoAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="studentDaoProxy"/>
<property name="pattern" value=".*Student"/>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
<!--定义切入点
<bean id="studentDaoImplPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value=".*Student"></property>
</bean> -->
<!--定义通知
<bean id="studentDaoAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="studentDaoProxy"/>
<property name="pointcut" ref="studentDaoImplPointcut"/>
</bean> -->
<!--定义代理工厂
<bean id="studentProxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="studentDaoImpl"/>
<property name="interceptorNames" value="studentDaoAdvisor"/>
<property name="proxyInterfaces" value="com.dao.StudentDao"/>
</bean> -->
</beans>
3)测试类
package com.proxy;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.dao.StudentDao;
import com.dao.impl.StudentDaoImpl;
public class TestProxy {
@Test
public void ProxyTest(){
ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext.xml");
StudentDao studentDao=new StudentDaoImpl();
studentDao=(StudentDao) ctx.getBean("studentDaoImpl");
studentDao.saveStudent();
studentDao.queryStudent();
}
}
基于schema的AOP
//没做测试
基于@AspectJ的AOP
applicationContext.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:p="http://www.springframework.org/schema/p"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
">
<!-- component-scan包含annotation-config,并且开启的注解更多 -->
<context:component-scan base-package="com" />
<!--Spring 默认不开启@Aspect注解 所以需要手动开启 -->
<aop:aspectj-autoproxy />
<!--定义实现类bean -->
<bean id="studentDaoImpl" class="com.dao.impl.StudentDaoImpl" />
</beans>
StudentDaoAspect .java
package com.proxy;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
//需要往Spring容器注入此bean,Spring才能识别并进行AOP的配置
@Component
public class StudentDaoAspect {
@Pointcut("execution(public void com.dao.impl.StudentDaoImpl.*Student())")
public void pointcut() {
}
@AfterReturning("pointcut()")
public void afterReturning() {
System.out.println("after");
}
@Before("pointcut()")
public void before() {
System.out.println("before");
}
}
StudentDaoImpl .java
package com.dao.impl;
import com.dao.StudentDao;
public class StudentDaoImpl implements StudentDao{
@Override
public void saveStudent() {
System.out.println("正在保存");
}
@Override
public void queryStudent() {
System.out.println("正在查询");
}
}
ProxyTest.java
package com.proxy;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.dao.StudentDao;
import com.dao.impl.StudentDaoImpl;
public class ProxyTest{
@Test
public void Test(){
ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext.xml");
StudentDao studentDao=new StudentDaoImpl();
studentDao=(StudentDao) ctx.getBean("studentDaoImpl");
studentDao.saveStudent();
studentDao.queryStudent();
}
}
打印结果
before
正在保存
after
before
正在查询
after
1)xml配置
<!-- component-scan包含annotation-config,并且开启的注解更多 -->
<context:component-scan base-package="com" />
<!--Spring 默认不开启@Aspect注解 所以需要手动开启 -->
<aop:aspectj-autoproxy />
2)切面声明
@Aspect
public class StudentDaoAspect{
...
}
3)切入点声明
切入点是连接点的集合,Spring只支持方法执行的连接点
Spring的切入点是@Pointcut+方法(必须是void类型的方法)
@Pointcut(value="切入点表达式",argNames="参数名列表")
public void pointcutName() {
}
vaule:切入点表达式
argNames:指定命名切入点方法的参数列表参数名字,可以用多个“,”分隔;这些参数将传给通知方法同名的参数
pointcutName:切入点名字,可以使用该名字进行引用该切入点表达式
@Pointcut进行命名切入点声明,指定目标方法第一个参数类型必须为String类型,并且参数类型不一致也是不匹配,通过argNames=“param”指定了把该匹配的目标方法参数传递到通知同名的参数上
4)声明通知
通知类型 | 公式 | 注意 |
---|---|---|
前置通知 | @Before( value=”切入点表达式或者命名切入点”, argNames=”参数列表参数名” ) | |
后置返回通知 | @AfterReturning( value=”切入点表达式或者命名切入点”, argNames=”参数列表参数名” pointcut=”切入点表达式或者命名切入点” returning=”返回值对应参数名” ) | pointcut的优先级比value高,会覆盖value |
后置异常通知 | @AfterThrowing( value=”切入点表达式或者命名切入点”, argNames=”参数列表参数名” pointcut=”切入点表达式或者命名切入点” throwing=”异常对应参数名” ) | pointcut会覆盖value |
后置最终通知 | @After( value=”切入点表达式或者命名切入点”, argNames=”参数列表参数名” ) | |
环绕通知 | @Around( value=”切入点表达式或者命名切入点”, argNames=”参数列表参数名” ) |