且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Spring【AOP模块】就这么简单(二)

更新时间:2022-10-09 08:28:46

工厂静态方法:

  • 把AOP加入IOC容器中
//把该对象加入到容器中
@Component
public class AOP {
    public void begin() {
        System.out.println("开始事务");
    }
    public void close() {
        System.out.println("关闭事务");
    }
}
  • 把UserDao放入容器中
@Component
public class UserDao {
    public void save() {
        System.out.println("DB:保存用户");
    }
}
  • 在配置文件中开启注解扫描,使用工厂静态方法创建代理对象
<?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"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <bean id="proxy" class="aa.ProxyFactory" factory-method="getProxyInstance">
        <constructor-arg index="0" ref="userDao"/>
        <constructor-arg index="1" ref="AOP"/>
    </bean>
    <context:component-scan base-package="aa"/>
</beans>

  • 测试,得到UserDao对象,调用方法
public class App {
    public static void main(String[] args) {
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("aa/applicationContext.xml");
        IUser iUser = (IUser) ac.getBean("proxy");
        iUser.save();
    }
}

Spring【AOP模块】就这么简单(二)

工厂非静态方法

上面使用的是工厂静态方法来创建代理类对象。我们也使用一下非静态的工厂方法创建对象

package aa;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * Created by ozc on 2017/5/11.
 */
public class ProxyFactory {
    public Object getProxyInstance(final Object target_, final AOP aop_) {
        //目标对象和关键点代码的类都是通过外界传递进来
        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_.close();
                        return returnValue;
                    }
                }
        );
    }
}

配置文件:先创建工厂,再创建代理类对象

<?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"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <!--创建工厂-->
    <bean id="factory" class="aa.ProxyFactory"/>
    <!--通过工厂创建代理-->
    <bean id="IUser" class="aa.IUser" factory-bean="factory" factory-method="getProxyInstance">
        <constructor-arg index="0" ref="userDao"/>
        <constructor-arg index="1" ref="AOP"/>
    </bean>
    <context:component-scan base-package="aa"/>
</beans>

Spring【AOP模块】就这么简单(二)

AOP的概述

Aop: aspect object programming  面向切面编程

  • 功能: 让关注点代码与业务代码分离!
  • 面向切面编程就是指: 对很多功能都有的重复的代码抽取,再在运行的时候往业务方法上动态植入“切面类代码”。

关注点:

  • 重复代码就叫做关注点。
// 保存一个用户
public void add(User user) { 
        Session session = null; 
        Transaction trans = null; 
        try { 
            session = HibernateSessionFactoryUtils.getSession();   // 【关注点代码】
            trans = session.beginTransaction();    // 【关注点代码】
            session.save(user);     // 核心业务代码
            trans.commit();     //…【关注点代码】
        } catch (Exception e) {     
            e.printStackTrace(); 
            if(trans != null){ 
                trans.rollback();   //..【关注点代码】
            } 
        } finally{ 
            HibernateSessionFactoryUtils.closeSession(session);   ////..【关注点代码】
        } 
   }

切面:

  • 关注点形成的类,就叫切面(类)!
public class AOP {
    public void begin() {
        System.out.println("开始事务");
    }
    public void close() {
        System.out.println("关闭事务");
    }
}

切入点:

  • 执行目标对象方法,动态植入切面代码。
  • 可以通过切入点表达式指定拦截哪些类的哪些方法; 给指定的类在运行的时候植入切面类代码

切入点表达式:

  • 指定哪些类的哪些方法被拦截

使用Spring AOP开发步骤

1) 先引入aop相关jar文件        (aspectj  aop优秀组件)

  • spring-aop-3.2.5.RELEASE.jar   【spring3.2源码】
  • 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】

注意: 用到spring2.5版本的jar文件,如果用jdk1.7可能会有问题

  • 需要升级aspectj组件,即使用aspectj-1.8.2版本中提供jar文件提供。

2) bean.xml中引入aop名称空间

引入jar包

引入4个jar包:

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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
</beans>

注解方式实现AOP编程

我们之前手动的实现AOP编程是需要自己来编写代理工厂的,现在有了Spring,就不需要我们自己写代理工厂了。Spring内部会帮我们创建代理工厂

  • 也就是说,不用我们自己写代理对象了。

因此,我们只要关心切面类、切入点、编写切入表达式指定拦截什么方法就可以了!

还是以上一个例子为案例,使用Spring的注解方式来实现AOP编程

在配置文件中开启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: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.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="aa"/>
    <!-- 开启aop注解方式 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

代码:

  • 切面类
@Component
@Aspect//指定为切面类
public class AOP {
    //里面的值为切入点表达式
    @Before("execution(* aa.*.*(..))")
    public void begin() {
        System.out.println("开始事务");
    }
    @After("execution(* aa.*.*(..))")
    public void close() {
        System.out.println("关闭事务");
    }
}
  • UserDao实现了IUser接口
@Component
public class UserDao implements IUser {
    @Override
    public void save() {
        System.out.println("DB:保存用户");
    }
}
  • IUser接口
public interface IUser {
    void save();
}
  • 测试代码:
public class App {
    public static void main(String[] args) {
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("aa/applicationContext.xml");
        //这里得到的是代理对象....
        IUser iUser = (IUser) ac.getBean("userDao");
        System.out.println(iUser.getClass());
        iUser.save();
    }
}

Spring【AOP模块】就这么简单(二)