1.手动实现AOP编程
AOP面向切面的编程:AOP可以实现业务代码与准备代码分离
代理工厂类
/**
* 动态代理
*(调用JDK中的API,在内存中动态的构建代理对象 目标对象必须实现接口时才能使用)
* @author wsk
*
*/
@Component
public class UserFactory_{
private IUserDao target;
private Aop aop;
public UserFactory_(IUserDao target, Aop aop){
this.target = target;
this.aop = aop;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
aop.begin();
Object returnValue = method.invoke(target, args);
aop.end();
return returnValue;
}
});
}
}
配置
<context:component-scan base-package="com.wsk.proxy_aop"></context:component-scan>
<!-- 工厂方法创建代理后对象,非静态 -->
<!-- 先创建工厂对象 调用带参数的构造器 -->
<bean id="userFactory_" class="com.wsk.proxy_aop.UserFactory_" >
<constructor-arg index="0" ref="userDao"></constructor-arg>
<constructor-arg index="1" ref="aop"></constructor-arg>
</bean>
<!-- 然后用工厂类的方法创建代理对象 -->
<bean id="proxy" factory-bean="userFactory_" factory-method="getProxyInstance"></bean>
2、AOP编程
关注点: 重复代码叫做关注点
切面:关注点形成的类,叫切面类
面向切面的编程,就是指对很多功能都有重复的代码抽取,在运行的时候往业务方法上动态植入切面代码。
切入点:执行目标对象方法,动态植入切面代码。
可以通过切入点表达式,指定拦截哪些类的哪些方法,给指定的类在运行的时候植入切面代码。
3.2 注解的方式实现AOP编程
(关键在于注解的切入点表达式@Pointcut(“execution(* cn.itcast.e_aop_anno..(..))”) 指定切入点表达式)
步骤:
1)引入AOP相关的jar文件
- spring-aop-3.2.5.RELEASE.jar 【spring3.2.5
- aopalliance.jar 【spring2.5源码/lib/aopalliance】
- aspectjweaver.jar 【spring2.5源码/lib/aspectj】或【aspectj-1.8.2\lib】
- aspectjrt.jar 【spring2.5源码/lib/aspectj】或【aspectj-1.8.2\lib】
2) bean.xml中引入aop名称空间
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
3) 开启aop注解
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.wsk.proxy_aop_note"></context:component-scan>
<!-- 开启AOP注解方式 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4) 使用注解
// 指定切入点表达式,拦截那些方法,即为那些类生成代理对象
@Aspect 指定一个类为切面类
@Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))") 指定切入点表达式
@Before("pointCut_()") 前置通知: 目标方法之前执行
@After("pointCut_()") 后置通知:目标方法之后执行(始终执行)
@AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行)
@AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行
@Around("pointCut_()") 环绕通知: 环绕目标方法执行
<!-- 开启aop注解方式 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
示例代码
// 注解加入到容器中,并指定当前类为切面类
@Component
@Aspect
public class Aop {
// 指定切入点表达式,拦截那些方法,即为那些类生成代理对象
@Before("execution(* com.wsk.proxy_aop_note.*.*(..))")
public void begin(){
System.out.println("开启事务");
}
@After("execution(* com.wsk.proxy_aop_note.*.*(..))")
public void end(){
System.out.println("提交事务");
}
}
或者写成
@Component
@Aspect
public class Aop {
// 指定切入点表达式,拦截那些方法,即为那些类生成代理对象
@Pointcut("execution(* com.wsk.proxy_aop_note.*.*(..))")
public void pointCut(){
}
@Before("pointCut()")
public void begin(){
System.out.println("开启事务");
}
@After("pointCut()")
public void end(){
System.out.println("提交事务");
}
}
测试类
/**
* 注解方式配置Aop切面编程
* 实现接口默认使用jdk代理,未实现接口的使用cglib代理
* @author wsk
*
*/
public class App {
ApplicationContext ac = new ClassPathXmlApplicationContext("com/wsk/proxy_aop_note/bean.xml");
@Test
public void testAop(){
// 目标对象实现接口使用JDK代理
IUserDao proxy = (IUserDao) ac.getBean("userDao");
System.out.println(proxy.getClass());
proxy.save();
// 目标对象没有实现接口使用Cglib代理
OrderDao orderDao = (OrderDao) ac.getBean("orderDao");
System.out.println(orderDao.getClass());
orderDao.save();
}
}
目标对象实现接口,Spring采用JDK代理,目标对象没有实现接口,Spring使用Cglib代理
3.3 XML方式实现AOP编程
1)、引入jar文件【aop相关jar 4个】
2)、引入aop名称空间
3)、 AOP配置
<!-- aop配置 -->
<aop:config>
<!-- 拦截指定方法 -->
<!-- 拦截指定包,及其子包下的所有方法
<aop:pointcut expression="execution(* com..*.*(..))" id="pt"/> -->
<!-- 拦截save开头的所有方法
<aop:pointcut expression="execution(* save*(..))" id="pt"/> -->
<!-- 拦截指定类的所有方法
<aop:pointcut expression="execution(* com.wsk.proxy_aop_xml.UserDao.*(..))" id="pt"/> -->
<aop:pointcut expression="execution(* com.wsk.proxy_aop_xml.*.*(..))" id="pt"/>
<!-- 切面 -->
<aop:aspect ref="aop">
<!-- 前置通知 -->
<aop:before method="begin" pointcut-ref="pt"/>
<aop:after method="end" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
切入点表达式
定位切入的方法
public(可选) (返回值类型) com.wsk.proxy_aop_xml.(类名).*(方法名)(..)