4:spring面向切面的编程

4spring面向切面的编程

Spring提供2个代理模式,一个是jdk代理,另一个cglib代理

1.若目标对象实现了若干接口spring使用JDKjava.lang.reflect.Proxy类代理。

2.若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。

 

注意:开发时尽量使用接口的编程,

(1)对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统。

(2)标记为final的方法不能够被通知。spring是为目标类产生子类。任何需要被通知的方法都被写,将通知织入。final方法是不允许重写的。

 (3) spring只支持方法连接点,不支持属性的连接点

 

 

1)配置:

要进行AOP编程,首先我们要在spring的配置文件中引入aop命名空间:

<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-3.0.xsd">

</beans>

 

Spring提供了两种切面使用方式,实际工作中我们可以选用其中一种:

基于XML配置方式进行AOP开发。

基于注解方式进行AOP开发。

 

SpringAOP编程,需要引入的jar

4:spring面向切面的编程

(2)基于XML方式的配置:测试代码

IUserService接口

public interface IUserService {

 

public void saveUser(String name,String password);

public void updateUser(String name,String password);

public void deleteUser(String name);

public String findUser();

}

 

UserServiceImpl实现类

public class UserServiceImpl implements IUserService {

 

public void saveUser(String name, String password) {

System.out.println("【新增】用户名:"+name+",密码:"+password);

}

 

public void updateUser(String name, String password) {

System.out.println("【修改】用户名:"+name+",密码:"+password);

}

 

public void deleteUser(String name) {

System.out.println("【删除】用户名:"+name);

}

 

public String findUser() {

System.out.println("【查询】用户");

return "小强";

}

 

 

}

 

测试类App.java

public class App {

 

public static void main(String[] args) {

//直接访问目标对象

//使用代理对象访问目标对象,当在spring的容器中添加<aop>

ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/e_xml/a_before/beans.xml");

IUserService userService = (IUserService)ac.getBean("userServiceImpl");

userService.saveUser("超级强""123");

userService.updateUser("超级强""123");

userService.deleteUser("超级强");

String str = userService.findUser();

System.out.println("str:"+str);

}

}

 

【1】前置通知

切面类Security

/**切面*/

public class Security {

 

/**通知*/

/**

 * 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型 (

 * 环绕通知需要定义第一个参数为ProceedingJoinPoint类型, 它是 JoinPoint 的一个子类)。

 * JoinPoint 接口提供了一系列有用的方法,

 * 比如 getArgs()(返回方法参数)、 

 * getThis()(返回代理对象)、

 * getTarget()(返回目标)、

 * getSignature()(返回正在被通知的方法相关信息)、

 *  toString() (打印出正在被通知的方法的有用信息)。

 */

public void checkSecurity(JoinPoint joinPoint){

System.out.println("正在执行验证...");

Object [] args = joinPoint.getArgs();

if(args!=null && args.length>0){

for(Object o:args){

System.out.println("参数:"+o);

}

}

System.out.println("代理对象:"+joinPoint.getThis().getClass());

System.out.println("目标对象:"+joinPoint.getTarget().getClass());

System.out.println("访问目标对象方法的名称:"+joinPoint.getSignature().getName());

System.out.println("spring容器中定义切入点的表达式:"+joinPoint.toString());

if(true){

throw new RuntimeException("抛出运行时异常!");

}

}

}

 

Spring容器(beans.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: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-3.0.xsd

               http://www.springframework.org/schema/aop

               http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!-- 创建目标对象 -->

    <bean id="userServiceImpl" class="cn.itcast.e_xml.a_before.UserServiceImpl"></bean>

    <!-- 声明切面 (无灵魂)-->

    <bean id="security" class="cn.itcast.e_xml.a_before.Security"></bean>

    

    <!-- spring的aop编程,所有的操作(切面、通知、切入点)都要放置到aop:config -->

    <aop:config>

     <!-- 

     定义个切面,此时切面的类具有了灵魂

     id:惟一标识

     ref:注入对象

      -->

     <aop:aspect id="aa" ref="security">

     <!-- 

     声明切入点

     id:切入点的惟一标识

     expression:切入点的表达式语言,指定项目中哪个类哪个方法作为切入点

      -->

     <aop:pointcut id="save" expression="execution(* cn.itcast.e_xml.a_before.UserServiceImpl.saveUser(..))" />

     <aop:pointcut id="update" expression="execution(* cn.itcast.e_xml.a_before.UserServiceImpl.updateUser(..))" />

     <!-- 

     定义通知(切入点要做的事情)

     前置通知:在访问目标对象方法之前,先执行通知定义的方法

     特点:如果代理对象(切面)中的方法(通知)抛出异常,此时不会执行目标对象

     pointcut-ref:注入切入点,这样才能让切入点关联通知

     * method:指定切面中定义的通知的方法

      -->

     <aop:before pointcut-ref="save" method="checkSecurity"/>

     <aop:before pointcut-ref="update" method="checkSecurity"/>

     </aop:aspect>

    </aop:config>

</beans>

你可能感兴趣的:(spring)