• spring注解、aop(二)


    使用注解配置spring

      1.导入 spring-aop-5.0.6.RELEASE.jar包

      2.为主配置文件引入新的命名空间 xmlns:context="http://www.springframework.org/schema/context"

    <?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"
           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-4.0.xsd">
    
        <!--指定扫描com.david.bean下的所有包所有类中的注解 -->
        <context:component-scan base-package="com.david.bean"></context:component-scan>
    
    </beans>

      3.在类中使用注解

    @Component("user")
    //相当于<bean name="user" class="com.david.bean.User" />
    public class User {
        private String name;
        private Integer age;
        private Car car;
    
        ...
    }

    注解后来又出现了三种,可以体现层级关系

    @Component("user")
    @Service("user") //service层
    @Controller("user") //web层
    @Repository("user") //dao层

    指定作用范围

    @Component("user")
    //相当于<bean name="user" class="com.david.bean.User" />
    @Scope(scopeName = "prototype")
    //相当于<bean name="user" class="com.david.bean.User" scope="prototype"></bean>

    值类型注入

    public class User {
        @Value("david") //字段注入 破坏了封装性
        private String name;
        private Integer age;
        private Car car;
    
        @Value("18") //set方法注入 推荐使用
        public void setAge(int age) {
            this.age = age;
        }
        ...
    }

    引用类型(对象)注入

    @Component("car")
    public class Car {
        @Value("奥拓")
        private String name;
        @Value("red")
        private String color;
        ...
    }
    @Component("user")
    public class User {
        @Autowired //自动装配 对象注入
        private Car car;
        ...
    }

    @autowired 自动装配的方式 如果匹配到多个类型一致的对象,无法选择具体注入哪一个对 如:

        <bean name="car2" class="com.david.bean.Car">
            <property name="name" value="奥迪"></property>
            <property name="color" value="black"></property>
        </bean>

    此时需要使用@Qualifier("car2")注解告诉容器具体注入哪个对象 和@autowired一起使用

        @Autowired
        @Qualifier("car2")
        private Car car;

    上面这种要使用两个注解,还有一个注解@Resource 可以手动指定注入哪个对象 

        @Resource(name="car2") //手动指定
        private Car car;

    初始化和销毁

    public class User {
        ...
        @PostConstruct //相当于init-method 对象创建后调用
        public void init(){
            System.out.println("init");
        }
    
        @PreDestroy //销毁前调用 相当于destory-method
        public void destory(){
            System.out.println("destory");
        }
        ...
    }

    aop:面向切面编程,是对oop面向对象编程的补充和完善。

    spring中的aop

      spring能够为容器中管理的对象生成动态代理对象。

    spring实现aop的原理

      1.动态代理(优先使用)

        被代理对象必须要实现接口,才能产生代理对象,如果没有接口将不能使用动态代理技术

      2.cglib代理(没有接口时)

        第三方代理技术,可以对任何类生成代理对象。代理的原理是对目标对象进行继承代理

    spring AOP 名词解释:

      1.Joinpoint连接点:目标对象中,所有可以增强的方法。(可以增强的方法)如:UserServiceImpl implements UserService 中实现的方法 save() delete()

      2.Pointcut切入点:目标对象中,已经增强的方法。(已增强的方法)如:已通过代理增强的save() 或delete() 可以单独指定某些增强或不增强。

      3.Advice通知/增强:需要增强的代码。(代理对象调用目标方法前后执行的代码)如://前增强 method.invoke(us,arg) //后增强。

      4.Target目标对象:被代理对象。如UserServiceImpl。

      5.Weaving织入:将通知织入(应用到)切入点的过程。

      6.Proxy代理:将通知织入道目标对象之后,形成代理对象。

    所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。

    基于spring的aop实现

    1.导包 aopalliance.jar aspectjweaver.jar  spring aop需要这两个包的支持 下载地址:

    http://www.java2s.com/Code/Jar/a/Downloadaopalliancejar.htm

    http://www.java2s.com/Code/Jar/a/Downloadaspectjweaverjar.htm

    2.准备目标对象

      先定义一个接口

    public interface IHelloWorld {
        void printHelloWorld();
        void doPrint();
    }

      在定义两个接口实现类

    public class HelloWorldImpl1 implements IHelloWorld
    {
        public void printHelloWorld()
        {
            System.out.println("Enter HelloWorldImpl1.printHelloWorld()");
        }
    
        public void doPrint()
        {
            System.out.println("Enter HelloWorldImpl1.doPrint()");
            return ;
        }
    }
    
    public class HelloWorldImpl2 implements IHelloWorld{
        public void printHelloWorld()
        {
            System.out.println("Enter HelloWorldImpl2.printHelloWorld()");
        }
    
        public void doPrint()
        {
            System.out.println("Enter HelloWorldImpl2.doPrint()");
            return ;
        }
    }

    3.准备通知

    package com.david.bean;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    
    public class MyAdvice {
        //前置通知-目标方法调用之前调用
        public void before() {
            System.out.println("前置通知");
        }
    
        //后置通知-目标方法之后调用,如果异常不会调用
        public void afterRuning() {
            System.out.println("后置通知,出现异常不会调用");
        }
    
        //环绕通知-在目标方法之前和之后都调用
        public void around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("环绕前通知");
            Object proceed = pjp.proceed();//调用目标方法
            System.out.println("环绕后通知");
        }
    
        //异常通知-如果出现异常就会被调用
        public void afterException(){
            System.out.println("出现异常");
        }
    
        //后置通知-目标方法之后调用,无论异常与否都会调用
        public void after() {
            System.out.println("后置通知,无论异常与否都会调用");
        }
    }

    4.配置进行织入,将通知织入目标对象中

    新建一个aop.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!--导入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"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        <!--配置目标对象 -->
        <bean id="helloWorldImpl1" class="com.david.bean.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.david.bean.HelloWorldImpl2" />
        <!--配置通知对象 -->
        <bean id="myAdvice" class="com.david.bean.MyAdvice" />
        <!--配置将通知织入目标对象 -->
        <aop:config>
            <!--配置切入点:所有方法都增强 -->
            <aop:pointcut id="allMethod" expression="execution(* com.david.bean.IHelloWorld.*(..))"></aop:pointcut>
            <aop:aspect id="advice" ref="myAdvice">
                <!--通知方法 -->
                <aop:before method="before" pointcut-ref="allMethod" />
                <aop:after-returning method="afterRuning" pointcut-ref="allMethod"></aop:after-returning>
                <aop:around method="around" pointcut-ref="allMethod"></aop:around>
                <aop:after method="after" pointcut-ref="allMethod" />
            </aop:aspect>
        </aop:config>
    </beans>

    5.编写测试类

        public static void main(String[] args) {
            ApplicationContext ac = new ClassPathXmlApplicationContext("aop.xml");
    
            IHelloWorld hw1 = (IHelloWorld)ac.getBean("helloWorldImpl1");
            IHelloWorld hw2 = (IHelloWorld)ac.getBean("helloWorldImpl2");
            hw1.printHelloWorld();
            System.out.println();
            hw1.doPrint();
    
            System.out.println();
            hw2.printHelloWorld();
            System.out.println();
            hw2.doPrint();
        }

    使用spring aop开发 就不需要我们手写动态代理代码了,还封装了cglib代理。可以对任何类进行代理增强。

    spring的aop注解配置

    <?xml version="1.0" encoding="UTF-8"?>
    <!--导入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"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        <!--配置目标对象 -->
        <bean id="helloWorldImpl1" class="com.david.bean.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.david.bean.HelloWorldImpl2" />
        <!--配置通知对象 -->
        <bean id="myAdvice" class="com.david.bean.MyAdvice" />
    
        <!--开启使用注解织入目标对象 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    
    </beans>

    通知类 使用注解设置

    @Aspect //表示该类是一个通知类
    public class MyAdvice {
        @Before("execution(* com.david.bean.IHelloWorld.*(..))") //是一个前置通知并指定切入点
        public void before() {
            System.out.println("前置通知");
        }
        @After("execution(* com.david.bean.IHelloWorld.*(..))")
        public void after() {
            System.out.println("后置通知,无论异常与否都会调用");
        }
    
        @AfterReturning("execution(* com.david.bean.IHelloWorld.*(..))")
        public void afterRuning() {
            System.out.println("后置通知,出现异常不会调用");
        }
    
        @Around("execution(* com.david.bean.IHelloWorld.*(..))")
        public void around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("环绕前通知");
            Object proceed = pjp.proceed();//调用目标方法
            System.out.println("环绕后通知");
        }
    
    }

    再次运行 效果一样的。 抽取切入点

    package com.david.bean;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    
    @Aspect //表示该类是一个通知类
    public class MyAdvice {
        //定义一个切入点规则
        @Pointcut("execution(* com.david.bean.IHelloWorld.*(..))")
        public void pc(){
    
        }
    
        @Before("MyAdvice.pc()")
        public void before() {
            System.out.println("前置通知");
        }
        @After("MyAdvice.pc()")
        public void after() {
            System.out.println("后置通知,无论异常与否都会调用");
        }
    
        @AfterReturning("MyAdvice.pc()")
        public void afterRuning() {
            System.out.println("后置通知,出现异常不会调用");
        }
    
        @Around("MyAdvice.pc()")
        public void around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("环绕前通知");
            Object proceed = pjp.proceed();//调用目标方法
            System.out.println("环绕后通知");
        }
    
    }
  • 相关阅读:
    html的输出&,空格,大小于号
    html如何修改hr水平直线的粗细
    LODOP指定window默认打印机和临时默认打印机
    微软面试题: 找出二叉树上任意两个结点的最近共同父结点。
    说说自己对hibernate一级、二级、查询、缓存的理解。
    MySql中添加用户,新建数据库,用户授权,删除用户,修改密码
    修改MySQL的默认密码的四种小方法
    java中Scanner的nextLine()和next()的区别
    JAVA中String字符串比较equals()和equalsIgnoreCase()的区别
    HashMap与HashTable的区别
  • 原文地址:https://www.cnblogs.com/baidawei/p/9082954.html
Copyright © 2020-2023  润新知