3-Spring AOP

AOP

1-什么是AOP

  • AOP Aspect Oriented Programing 面向切面编程

  • AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视,事务管理、安全检查、缓存)。

2-AOP的底层实现原理

3-AOP的相关术语

public class USerDaoImpl implements UserDao{
    public void save(User user){
    
    }
    public void update(User user){
    
    }
    public void find( ){
    
    }
    public void delete(User user){
    
    }
}

Joinpoint (连接点):指的是可以被拦截的点。增删改查这些方法都可以被增强,这些方法称为是连接点。

Pointcut (切入点):指的是真正被拦截的点。只想对save方法进行增强(做权限校验),save方法称为是切入点。

Advice (通知):拦截后要做的事情。对save方法进行校验,权限校验的方法称为通知。

Target(目标):被增强的对象

weaving(织入):将Advice应用到Target的过程。将权限校验应用到UserDaoImpl的Save方法的这个过程。

Proxy(代理):被应用了增强后,产生了一个代理对象。

Aspect(切面):就是切入点和通知的组合。

4.JDK动态代理

测试改代码需要导入Juint的jar包

public interface UserDao {
    public void save();

    public void update();

    public void delete();

    public void find();
}

* * *
public class UserDaoImpl implements UserDao {
    public void save() {
        System.out.println("保存用户...");
    }

    public void update() {
        System.out.println("修改用户...");
    }

    public void delete() {
        System.out.println("删除用户...");
    }

    public void find() {
        System.out.println("查询用户...");
    }
}

* * *
public class MyJdkProxy implements InvocationHandler{
    private UserDao userDao;

    public MyJdkProxy(UserDao userDao){
        this.userDao = userDao;
    }

    public Object createProxy(){
        Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(),this);
        return proxy;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if("save".equals(method.getName())){
            System.out.println("权限校验...");
            return method.invoke(userDao,args);
        }
        return method.invoke(userDao,args);
    }
}

* * *
public class SpringDemo1 {
    @Test
    public void demo1(){
        UserDao userDao = new UserDaoImpl();

        UserDao proxy = (UserDao)new MyJdkProxy(userDao).createProxy();
        proxy.save();
        proxy.update();
        proxy.delete();
        proxy.find();
    }
}

5.使用CGLIB生成代理

pom.xml核心jar包
<dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
     <!--aop联盟的包-->
    <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>
    <!--spring aop的包-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
public class ProductDao {
    public void save(){
        System.out.println("保存商品...");
    }

    public void update(){
        System.out.println("修改商品...");
    }

    public void delete(){
        System.out.println("删除商品...");
    }

    public void find(){
        System.out.println("查询商品...");
    }
}

* * *
public class MyCglibProxy implements MethodInterceptor{

    private ProductDao productDao;

    public MyCglibProxy(ProductDao productDao){
        this.productDao = productDao;
    }

    public Object createProxy(){
        // 1.创建核心类
        Enhancer enhancer = new Enhancer();
        // 2.设置父类
        enhancer.setSuperclass(productDao.getClass());
        // 3.设置回调
        enhancer.setCallback(this);
        // 4.生成代理
        Object proxy = enhancer.create();
        return proxy;
    }

    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        if("save".equals(method.getName())){
            System.out.println("权限校验===================");
            return methodProxy.invokeSuper(proxy,args);
        }
        return methodProxy.invokeSuper(proxy,args); //调用父类
    }
}

* * *
public class SpringDemo2 {

    @Test
    public void demo1(){
        ProductDao productDao = new ProductDao();

        ProductDao proxy = (ProductDao) new MyCglibProxy(productDao).createProxy();
        proxy.save();
        proxy.update();
        proxy.delete();
        proxy.find();
    }
}

6-代理知识总结

1- Spring在运行期,生成动态代理对象,不需要特殊的编译器

2-Spring AOP的底层就是通过JDK动态代理或CGLib动态代理技术 为目标Bean
执行横向织入.

  • 若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类
    代理。
  • 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。

3-程序中应优先对接口创建代理,便于程序解耦维护

4-标记为final的方法,不能被代理,因为无法进行覆盖

  • JDK动态代理,是针对接口生成子类,接口中方法不能使用final修饰
  • CGLib 是针对目标类生产子类,因此类或方法 不能使final的

5-Spring只支持方法连接点,不提供属性连接

6-Spring AOP增强类型

1-前置通知

  • 在目标方法执行前实施增强

2-后置通知

  • 在目标方法执行后实施增强

3-环绕通知

  • 在目标方法执行前后实施增强

4-异常抛出通知

  • 在方法抛出异常后实施增强

7- Spring AOP切面类型

1.Advisor : 代表一般切面,Advice本身就是一个切面,对目标类所有方法进
行拦截。

public interface StudentDao {
    public void find();

    public void save();

    public void update();

    public void delete();
}

* * *
public class StudentDaoImpl implements  StudentDao {
    public void find() {
        System.out.println("学生查询...");
    }

    public void save() {
        System.out.println("学生保存...");
    }

    public void update() {
        System.out.println("学生修改...");
    }

    public void delete() {
        System.out.println("学生删除...");
    }
}

* * *
public class MyBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("前置增强======================");
    }
}

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

    // @Resource(name="studentDao")
    @Resource(name="studentDaoProxy")
    private StudentDao studentDao;

    @Test
    public void demo1(){
        studentDao.find();
        studentDao.save();
        studentDao.update();
        studentDao.delete();
    }
}
<?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="studentDao" class="com.imooc.aop.demo3.StudentDaoImpl"/>

    <!--前置通知类型=====================-->
    <bean id="myBeforeAdvice" class="com.imooc.aop.demo3.MyBeforeAdvice"/>

    <!--Spring的AOP 产生代理对象-->
    <bean id="studentDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--配置目标类-->
        <property name="target" ref="studentDao"/>
        <!--实现的接口-->
        <property name="proxyInterfaces" value="com.imooc.aop.demo3.StudentDao"/>
        <!--采用拦截的名称-->
        <property name="interceptorNames" value="myBeforeAdvice"/>
        <property name="optimize" value="true"></property>
    </bean>
</beans>

2.PointcutAdvisor : 代表具有切点的切面,可以指定拦截目标类哪些方法

3.IntroductionAdvisor : 代表引介切面,针对引介通知而使用切面

猜你喜欢

转载自www.cnblogs.com/Guard9/p/11105503.html
今日推荐