Spring03

1.代码存在的问题

2.引出代理模式

3.静态代理

4.动态代理

5.AOP的思想和概念

6.pointcut语法

7.aop的xml配置

8.不同时机的增强

9.获取增强的参数

10.aop的注解配置

 

一、代码存在的问题

案例:每一个业务方法都要处理事务.

1、pom.xml参考前面,有的依赖是多余的。添加了lombok

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xj</groupId>
    <artifactId>Spring03</artifactId>
    <version>1.0.0</version>

    <properties>
        <!--定义全局变量,变量名为:project.spring.version-->
        <project.spring.version>5.0.0.RELEASE</project.spring.version>
    </properties>


    <dependencies>
        <!--Spring-core-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${project.spring.version}</version>
        </dependency>
        <!--Spring-beans-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${project.spring.version}</version>
        </dependency>
        <!--Spring-test-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${project.spring.version}</version>
        </dependency>
        <!--Spring-expression-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${project.spring.version}</version>
        </dependency>
        <!--Spring-context-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${project.spring.version}</version>
        </dependency>
        <!--Spring-aop-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${project.spring.version}</version>
        </dependency>

        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>


        <!--德鲁伊连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--mysql连接驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
        </dependency>

    </dependencies>


    <build>
        <!--从哪个地方加载配置文件-->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

</project>

2、事务管理器TransactionManager

package com.xj.tx;

/**
 * Created by Administrator on 2019/12/29 0029.
 */
public class TransactionManager {

    public void begin(){
        System.out.println("开启事务");
    }

    public void commit(){
        System.out.println("提交事务");
    }

    public void rollback(){
        System.out.println("回滚事务");
    }
}

3、dao

package com.xj.dao;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
public interface IUserDao {
    void save();
    void update();
}
package com.xj.dao.impl;

import com.xj.dao.IUserDao;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
public class UserDaoImpl implements IUserDao{
    public void save() {
        System.out.println("保存用户");
    }

    public void update() {
        System.out.println("更新用户");
        System.out.println(1/0);//出现异常
    }
}

4、service

package com.xj.service;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
public interface IUserService {
    void save();
    void update();
}
package com.xj.service.impl;

import com.xj.dao.IUserDao;
import com.xj.service.IUserService;
import com.xj.tx.TransactionManager;
import lombok.Setter;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
public class UserServiceImpl implements IUserService{

    @Setter
    private IUserDao dao;

    @Setter
    private TransactionManager txManager;

    public void save() {
        try{
            //开启事务
            txManager.begin();
            //业务操作
            dao.save();
            //提交事务
            txManager.commit();
        }catch(Exception e){
            //回滚事务
            txManager.rollback();
        }
    }

    public void update() {
        try{
            //开启事务
            txManager.begin();
            //业务操作
            dao.update();
            //提交事务
            txManager.commit();
        }catch(Exception e){
            //回滚事务
            txManager.rollback();
        }
    }
}

5、applicationContext

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--事务管理器-->
    <bean id="txManager" class="com.xj.tx.TransactionManager"></bean>

    <bean id="dao" class="com.xj.dao.impl.UserDaoImpl"></bean>

    <bean id="service" class="com.xj.service.impl.UserServiceImpl">
        <property name="dao" ref="dao"/>
        <property name="txManager" ref="txManager"/>
    </bean>
</beans>

6、测试类

package com.xj;

import com.xj.service.IUserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class App {

    @Autowired
    private IUserService service;

    @Test
    public void testSave(){
        service.save();
    }

    @Test
    public void testUpdate(){
        service.update();
    }

}

       存在的问题:   每一个Service实现类中的方法,都得需要处理事务,而这些处理事务的代码结构其实是相同的,存在着代码重复的.  

       问题1: 处理事务的代码结构重复.  

       问题2: 在业务方法中只需要处理业务功能即可,不该处理事务(责任分离思想). 

二、引出代理模式

从生活中去寻找解决方案,所以第一步找一个相似的案例:房屋中介案例

房东做了很多重复的并且不应该自己去做的事情:带你看房,商量租金,交钥匙. 她最感兴趣的是签合同和收房租. 房东就好比是Service实现类.

       真实生活中有一种房屋中介是这样的,租客根本就不知道房东是谁,一切签合同、交租金、交钥匙等操作都直接和中介公司发生。我们把这种模式称之为代理模式。

       代理模式:客户端直接使用的都是代理对象,不知道目标对象是谁,此时代理对象可以在客户端和目标对象之间起到中介的作用。

        1、代理对象完全包含目标对象,客户端使用的都是代理对象的方法,和目标对象没有直接关系;

        2、代理模式的职责:把不是目标对象该做的事情从目标对象上撇开——职责清晰;

       静态代理:在程序运行前就已经存在代理类的字节码文件,代理对象和目标对象的关系在运行前就确定了。

       动态代理:动态代理类是在程序运行期间由JVM通过反射等机制动态的生成的,所以不存在代理类的字节码文件。代理对象和真实对象的关系是在程序运行事情才确定的。

三、静态代理

静态代理:在程序运行前就已经存在代理类的字节码文件,代理对象和真实对象的关系在运行前就确定了。

新增一个代理类

package com.xj.proxy;

import com.xj.service.IUserService;
import com.xj.tx.TransactionManager;
import lombok.Setter;

/**
 * Created by Administrator on 2019/12/29 0029.
 */
public class UserServiceImplProxy implements IUserService{  //代理类

    @Setter
    private IUserService target;
    
    @Setter
    private TransactionManager txManager;

    public void save() {
        try{
            //开启事务
            txManager.begin();
                    //业务操作
                    target.save();
            //提交事务
            txManager.commit();
        }catch(Exception e){
            //回滚事务
            txManager.rollback();
        }
    }

    public void update() {
        try{
            //开启事务
            txManager.begin();
                    //业务操作
                    target.update();
            //提交事务
            txManager.commit();
        }catch(Exception e){
            //回滚事务
            txManager.rollback();
        }
    }
}

修改真实类

package com.xj.service.impl;

import com.xj.dao.IUserDao;
import com.xj.service.IUserService;
import lombok.Setter;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
public class UserServiceImpl implements IUserService{

    @Setter
    private IUserDao dao;

    public void save() {
        dao.save();
    }

    public void update() {
        dao.update();
    }
}

修改applicationContext

    <!--事务管理器-->
    <bean id="txManager" class="com.xj.tx.TransactionManager"></bean>

    <bean id="dao" class="com.xj.dao.impl.UserDaoImpl"></bean>

    <!--目标对象-->
    <bean id="service" class="com.xj.service.impl.UserServiceImpl">
        <property name="dao" ref="dao"/>
    </bean>

    <!--代理对象-->
    <bean id="proxy" class="com.xj.proxy.UserServiceImplProxy">
        <property name="txManager" ref="txManager"/>
        <property name="target" ref="service"/>
    </bean>

修改测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class App {

    @Autowired
    @Qualifier("proxy")//存在两个实现类,要指定给代理对象的那个实现类
    private IUserService service;

    @Test
    public void testSave(){
        service.save();
    }

    @Test
    public void testUpdate(){
        service.update();
    }
}

静态代理优缺点:

       优点: 1.业务类只需要关注业务逻辑本身,保证了业务类的重用性。     2.把真实对象隐藏起来了,保护真实对象

       缺点: 1.代理对象的某个接口只服务于某一种类型的对象,也就是说每一个真实对象都得创建一个代理对象。     2.如果需要代理的方法很多,则要为每一种方法都进行代理处理。   3.如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

四、动态代理

        动态代理是在程序运行期间由JVM通过反射等机制动态的创建出代理对象的字节码。代理对象和真实对象的关系是在程序运行时才确定的。

       动态代理是AOP的原理

1.jdk动态代理

JDK动态代理API分析:

      1、java.lang.reflect.Proxy 类: Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。

       主要方法:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler hanlder)

       方法职责:为指定类加载器、一组接口   及  调用处理器生成动态代理类实例 

       参数:    loader :类加载器               interfaces:目标对象实现的接口                  hanlder:代理执行处理器

       返回:动态生成的代理对象

1、添加依赖,事务管理器,参考上面案例

2、dao

package com.xj.dao;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
public interface IUserDao {
    void save();
    void update();
}
package com.xj.dao.impl;

import com.xj.dao.IUserDao;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
public class UserDaoImpl implements IUserDao{
    public void save() {
        System.out.println("保存用户");
    }

    public void update() {
        System.out.println("更新用户");
        System.out.println(1/0);//出现异常
    }
}

3、service

package com.xj.service;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
public interface IUserService {
    void save();
    void update();
}
package com.xj.service.impl;

import com.xj.dao.IUserDao;
import com.xj.service.IUserService;
import lombok.Setter;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
public class UserServiceImpl implements IUserService{

    @Setter
    private IUserDao dao;

    public void save() {
        dao.save();
    }

    public void update() {
        dao.update();
    }
}

4、代理类

package com.xj.proxy;

import com.xj.tx.TransactionManager;
import lombok.Setter;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Created by Administrator on 2019/12/29 0029.
 */
public class JDKProxy implements InvocationHandler{

    @Setter
    private Object target;//可以给任意的目标做代理,只要目标实现了接口

    @Setter
    private TransactionManager txManager;

    //获取代理对象
    public Object getProxy(){

        /*
        * 第一个参数:类加载器
        * 第二个参数:目标对象实现的接口的字节码数据对象  getClass获取字节码对象
        * 第三个参数:实现了InvocationHandler接口的类的对象
        * */
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        try{
            //开启事务
            txManager.begin();
            //执行业务方法
            method.invoke(target,args);
            //提交事务
            txManager.commit();
        }catch (Exception e){
            //回滚事务
            txManager.rollback();
        }
        return null;
    }
}

5、配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--事务管理器-->
    <bean id="txManager" class="com.xj.tx.TransactionManager"></bean>

    <bean id="dao" class="com.xj.dao.impl.UserDaoImpl"></bean>

    <!--目标对象-->
    <bean id="service" class="com.xj.service.impl.UserServiceImpl">
        <property name="dao" ref="dao"/>
    </bean>

    <!--事务增强的代理类-->
    <bean id="jdkProxy" class="com.xj.proxy.JDKProxy">
        <property name="target" ref="service"/>
        <property name="txManager" ref="txManager"/>
    </bean>
</beans>

6、测试类

package com.xj;

import com.xj.proxy.JDKProxy;
import com.xj.service.IUserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class App {

    @Autowired
    private JDKProxy jdkProxy;

    @Test
    public void testSave(){
        IUserService proxy = (IUserService) jdkProxy.getProxy();
        proxy.save();
    }

    @Test
    public void testUpdate(){
        IUserService proxy = (IUserService) jdkProxy.getProxy();
        proxy.update();
    }

}

JDK动态代理:

        1,代理的对象必须要实现接口

        2,需要为每个对象创建代理对象;

        3,动态代理的最小单位是类(类中所有的方法都会被代理);

JDK动态代理总结

       1,JAVA动态代理是使用java.lang.reflect包中的Proxy类与InvocationHandler接口这两个来完成的。

        2,要使用JDK动态代理,必须要定义接口。

        3,JDK动态代理将会拦截所有pubic的方法(因为只能调用接口中定义的方法),这样即使在接口中增加了新的方法,不用修改代码也会被拦截。

        4,如果只想拦截一部分方法,可以在invoke方法中对要执行的方法名进行判断。

2.jdk动态代理的实现原理


 

3.cglib的动态代理

       针对于没有接口的类,如何做代理:cglib都是针对没有接口,做动态代理的.

       原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

package com.xj.cglib;

import com.xj.service.impl.UserServiceImpl;
import com.xj.tx.TransactionManager;
import lombok.Setter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;

import java.lang.reflect.Method;

/**
 * Created by Administrator on 2019/12/29 0029.
 */
public class CglibProxy implements InvocationHandler{

    @Setter
    private Object target;

    @Setter
    private TransactionManager txManager;

    public Object getProxy(){
        Enhancer enhancer = new Enhancer();

        enhancer.setSuperclass(UserServiceImpl.class);
        enhancer.setCallback(this);
        //返回一个代理对象
        return enhancer.create();
    }

    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        try{
            //开启事务
            txManager.begin();
            //执行业务方法
            method.invoke(target,objects);
            //提交事务
            txManager.commit();
        }catch (Exception e){
            //回滚事务
            txManager.rollback();
        }
        return null;
    }
}
    <bean id="cglibProxy" class="com.xj.cglib.CglibProxy">
        <property name="target" ref="service"/>
        <property name="txManager" ref="txManager"/>
    </bean>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class App {

    @Autowired
    private JDKProxy jdkProxy;

    @Autowired
    private CglibProxy cglibProxy;

    @Test
    public void testSave(){
       /* IUserService proxy = (IUserService) jdkProxy.getProxy();
        System.out.println(proxy.getClass());
        proxy.save();*/
        UserServiceImpl proxy = (UserServiceImpl)cglibProxy.getProxy();
        proxy.save();
    }

    @Test
    public void testUpdate(){
        /*IUserService proxy = (IUserService) jdkProxy.getProxy();
        proxy.update();*/
        UserServiceImpl proxy = (UserServiceImpl)cglibProxy.getProxy();
        proxy.update();
    }

}

CGLIB代理总结

       1,CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。

       2,要求类不能是final的,要拦截的方法要是非final、非static、非private的。

       3,动态代理的最小单位是类(所有类中的方法都会被处理);

在Spring中:

       若目标对象实现了若干接口,Spring就会使用JDK动态代理。

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

       对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统,也更符合面向接口编程规范。

五、AOP的思想和概念

什么叫做AOP:Aspect oritention programming(面向切面编程)

       把一个个的横切关注点(这些零散存在于业务方法中的功能代码,我们称之为横切面关注点)放到某个模块中去,称之为切面。那么每一个的切面都能影响业务的某一种功能,切面的目的就是功能增强,如日志切面就是一个横切关注点,应用中许多方法需要做日志记录的只需要插入日志的切面即可。这种面向切面编程的思想就是AOP思想了。

              

       AOP的目的: AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来, 便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

      AOP的优势: 降低模块的耦合度、使系统容易扩展、更好的代码复用性    说人话: 把多个方法前/后的共同代码抽离出来,使用动态代理机制来控制,先执行抽离出来的代码,再执行每一个真实方法.

      Spring的AOP使用动态代理实现: 如果一个类实现了接口,那么spring就使用JDK的动态代理完成AOP; 如果一个类没有实现接口,那么spring就是用cglib完成AOP;

      AOP当中的概念:

            Joinpoint:连接点,被拦截到需要被增强的方法。where:去哪里做增强

            Pointcut:切入点,哪些包中的哪些类中的哪些方法,可认为是连接点的集合。where:去哪些地方做增强

            Advice:增强,当拦截到Joinpoint之后,在方法执行的什么时机(when)做什么样(what)的增强。

            Aspect:切面,Pointcut+Advice,去哪些地方+在什么时候+做什么增强

            Weaving:织入,把Advice加到Target上之后,创建出Proxy对象的过程。

六、pointcut语法

      Pointcut语法: AOP思想本应该由SUN公司来制定规范,但是被AOP联盟捷足先登了. AOP联盟制定AOP规范,首先就要解决一个问题,怎么表示在哪些方法上增强—— AspectJ(语言)。

      AspectJ切入点语法如下: execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)

      翻译成中文: execution(<访问修饰符>? <返回类型> <声明类型>? <方法名>(<参数>) <异常>?)

      通配符:    

          *   :匹配任何部分,只能表示一个单词  

          ..    : 可用于全限定名中和方法参数中,分别表示子包0到N个参数

         

七、aop的xml配置

1、添加依赖参考上面,另外新增。

        <!-- aspectjweaverr -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>

2、事务管理器,参考上面,新增destory方法

package com.xj.tx;

/**
 * Created by Administrator on 2019/12/29 0029.
 */
public class TransactionManager {

    public void begin(){
        System.out.println("开启事务");
    }

    public void commit(){
        System.out.println("提交事务");
    }

    public void rollback(){
        System.out.println("回滚事务");
    }

    public void destory(){
        System.out.println("释放资源");
    }
}

3、dao

package com.xj.dao;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
public interface IUserDao {
    void save();
    void update();
}
package com.xj.dao.impl;

import com.xj.dao.IUserDao;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
public class UserDaoImpl implements IUserDao{
    public void save() {
        System.out.println("保存用户");
    }

    public void update() {
        System.out.println("更新用户");
        System.out.println(1/0);//出现异常
    }
}

4、service

package com.xj.service;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
public interface IUserService {
    void save();
    void update();
}
package com.xj.service.impl;

import com.xj.dao.IUserDao;
import com.xj.service.IUserService;
import lombok.Setter;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
public class UserServiceImpl implements IUserService{

    @Setter
    private IUserDao dao;

    public void save() {
        dao.save();
    }

    public void update() {
        dao.update();
    }
}

5、配置xml文件,(添加aop命名空间,配置切入点,切入面)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/aop
                http://www.springframework.org/schema/aop/spring-aop.xsd
">

    <!--事务管理器-->
    <bean id="txManager" class="com.xj.tx.TransactionManager"></bean>

    <bean id="dao" class="com.xj.dao.impl.UserDaoImpl"></bean>

    <!--目标对象-->
    <bean id="service" class="com.xj.service.impl.UserServiceImpl">
        <property name="dao" ref="dao"/>
    </bean>

    <!--配置AOP-->
    <aop:config >

        <!--
            pointcut:切入点:哪些包里的哪些类中的哪些方法,需要被增强
        -->
        <aop:pointcut id="txPointxut" expression="execution( * com.xj.service.IUserService.*(..))"></aop:pointcut>

        <!--
            配置切面:Aspect = pointcut+Advice
         -->
        <aop:aspect ref="txManager">
            <!--前置增强-->
            <aop:before method="begin" pointcut-ref="txPointxut"/>
            <!--后置增强-->
            <aop:after-returning method="commit" pointcut-ref="txPointxut"/>
            <!--异常增强-->
            <aop:after-throwing method="rollback" pointcut-ref="txPointxut"/>
            <!--最终增强-->
            <aop:after method="destory" pointcut-ref="txPointxut"/>
        </aop:aspect>
    </aop:config>
</beans>

6、测试类

package com.xj;

import com.xj.service.IUserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class App {

    @Autowired
    private IUserService service;

    @Test
    public void testSave(){
        service.save();
    }

    @Test
    public void testUpdate(){
        service.update();
    }
}

小结:

     1.使用Spring的aop,首先要导入aspect包

     2.Spring配置文件中添加aop的命名空间.

     3.xml配置aop时,时刻记得要配置where,when,what.

八、不同时机的增强

各种不同的增强

       aop:before(前置增强):在方法执行之前执行增强;

       aop:after-returning(后置增强):在方法正常执行完成之后执行增强;

       aop:after-throwing(异常增强):在方法抛出异常退出时执行增强;

       aop:after(最终增强):在方法执行之后执行,相当于在finally里面执行;可以通过配置throwing来获得拦截到的异常信息

       aop:around(环绕增强):最强大的一种增强类型。 环绕增强可以在方法调用前后完成自定义的行为,

       环绕增强有两个要求:                     

              1,方法要返回一个Object(返回的结果)                      

              2,方法的第一个参数是ProceedingJoinPoint(可以继续向下传递的切入点)

案例:使用环绕增强,在七的代码上进行添加修改

1、在事务管理器中添加around方法

    public void around(ProceedingJoinPoint pj) {
        try {

            System.out.println("开启事务");

            //执行被增强的方法
            pj.proceed();//这个方法可以有一个返回值,比如 save方法返回值是Integer  这就可以返回一个值Object i =pj.proceed() ,然后return i;
            //注:around返回类型要写成Object;    update没有返回值,不影响

            System.out.println("提交事务");

        } catch (Throwable e) {
            System.out.println("回滚事务");
        } finally {
            System.out.println("释放资源");
        }
    }

2、修改配置文件

    <!--配置AOP-->
    <aop:config >

        <!--
            pointcut:切入点:哪些包里的哪些类中的哪些方法,需要被增强
        -->
        <aop:pointcut id="txPointxut" expression="execution( * com.xj.service.IUserService.*(..))"></aop:pointcut>

        <!--
            配置切面:Aspect = pointcut+Advice
         -->
        <aop:aspect ref="txManager">
            <!--前置增强-->
           <!-- <aop:before method="begin" pointcut-ref="txPointxut"/>-->
            <!--后置增强-->
           <!-- <aop:after-returning method="commit" pointcut-ref="txPointxut"/>-->
            <!--异常增强-->
           <!-- <aop:after-throwing method="rollback" pointcut-ref="txPointxut"/>-->
            <!--最终增强-->
            <!--<aop:after method="destory" pointcut-ref="txPointxut"/>-->
            
            <!--环绕增强-->
            <aop:around method="around" pointcut-ref="txPointxut"/>
        </aop:aspect>

九、获取增强的参数

1、在增强方法中获取异常的信息。        

        <aop:after-throwing>的标签中添加throwing=“ex”的属性        

        增强方法rollback中,添加形式参数:Exception ex。        

        则,形参ex中就自动注入了异常对象。

注意:throwing属性的值,必须与方法中形参的名字相同 

案例:执行update方法

(1)使用环绕增强,获取异常参数

(2)使用其他增强方式获取增强参数

2、在增强方法中,获取被增强方法的信息:

       Spring AOP提供org.aspectj.lang.JoinPoint类,作为增强方法的第一个参数。

       JoinPoint  :提供访问当前被增强方法的真实对象、代理对象、方法参数等数据。

       ProceedingJoinPoint:JinPoint子类,只用于环绕增强中,可以处理被增强方法。

十、aop的注解配置

1、添加依赖,参考上面

2、事务管理器

package com.xj.tx;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;

/**
 * Created by Administrator on 2019/12/29 0029.
 */
@Aspect
public class TransactionManager {

    @Pointcut("execution( * com.xj.service.IUserService.*(..))")
    public void tx(){}

    @Before("tx()")
    public void begin(JoinPoint jp){//获取增强参数
        System.out.println("开启事务");
        System.out.println(jp.getThis());
    }

    @AfterReturning("tx()")
    public void commit(){
        System.out.println("提交事务");
    }

    @AfterThrowing(value="tx()",throwing = "ex")//获取异常参数
    public void rollback(Exception ex){
        System.out.println("回滚事务");
        System.out.println(ex.getMessage());
    }

    @After("tx()")
    public void destory(){
        System.out.println("释放资源");
    }
}

3、dao和servive参考上个例子

4、配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--事务管理器-->
    <bean id="txManager" class="com.xj.tx.TransactionManager"></bean>

    <bean id="dao" class="com.xj.dao.impl.UserDaoImpl"></bean>

    <!--目标对象-->
    <bean id="service" class="com.xj.service.impl.UserServiceImpl">
        <property name="dao" ref="dao"/>
    </bean>

    <!--aop注解解析器-->
    <aop:aspectj-autoproxy/>

</beans>

5、测试类

package com.xj;

import com.xj.service.IUserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * Created by Administrator on 2019/12/27 0027.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class App {

    @Autowired
    private IUserService service;

    @Test
    public void testSave(){
        service.save();
    }

    @Test
    public void testUpdate(){
        service.update();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值