JAVA:SSM\Spring框架\IOC和AOP

Spring是什么

  • Spring是分层的java SE/EE应用轻量级框架,以IOC(Inverse Of Control:控制反转)和AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现出springMVC和持久层SpringJDBC以及业务层事务管理等众多的企业家应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架

Spring的优势

  • 方便解耦,简化开发
    通过spring提供的IOC容器,可以将对象间的依赖关系交由spring进行控制,避免硬编码所造成的过度程序耦合.用户也不必再为模式类,属性文件解析等这些底层的需求编写代码,可以更专注于上层的应用.

  • AOP编程
    通过spring的AOP功能,方便进行面向切面的编程,如多不容易用传统OOP实现的功能可以通过AOP轻松应对

  • 声明事务支持
    可以将我们从单调的烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量

  • 方便程序的测试
    可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情

  • 方便集成各种优秀的框架
    spring可以降低各种框架的使用难度,提供了对各种优秀框架的支持(Struts、Hibernate、Hessian、Quartz等)

  • 降低了JAVAEE API的使用难度
    Spring对JAVAEE API进行了轻量的封装,使这些API的使用难度大大降低

  • JAVA源码是经典学习范例
    spring的源码设计精妙,结构清晰,处处体现着大佬对JAVA设计模式灵活运用以及对JAVA技术的高深造诣
    高内聚低耦合

  • 在软件工程中,耦合指的就是对象之间依赖性,对象之间的耦合越高,维护成本越高.因此对象的设计应使类和构件之间的耦合最小.软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准.模块划分的一个准则就是高内聚低耦合

  • 内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从 功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。

  • 耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。 程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之 间的相互依存度却要不那么紧密。

  • 内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块同其他模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合。
    Spring核心之IOC
    Ioc—Inversion of Control,即"控制反转",是一种设计思想.我们在编写程序时,通过控制反转,将对象的创建交给了spring,但是代码中不可能出现没有依赖的情况,IOC解耦只是降低他们的依赖关系,但不会消除.例如,业务层仍会调用持久层的方法,那这种业务层和持久层的依赖关系,在使用spring之后,就交给spring来维护.也就是说,坐等框架把持久层对象传入业务层,而不用我们自己去获取

IOC细节
容器对象的类结构

  • beanFactory是spring容器的顶层接口

  • 接口ApplicationConetext是beanFactory子接口
    实现类:ClassPathXmlApplicationContext --从类路径之下读取配置文件(常用)

  • BeanFactory与ApplicationContext区别

Resource resource=new ClassPathResource("beans.xml");
//BeanFactory:创建容器对象时,只是加载了配置文件,没有创建对象
//获取对象时:创建对象
BeanFactory beanFactory=new XmlBeanFactory(resource);
object userDao =beanFactory.getBean("userDao");
Syetem.out.println(userDao);
//创建spring的IOC容器
//在创建容器对象时,创建对象(常用)
//ApplicationContext:在创建容器时只创建单例模式的对象
//多例模式的对象,在获取时创建
ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
object userDao2 =ac.getBean("userDao");
System.out.println(userDao2);

getBean方法

ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//根据名称获取该对象
//object userDao =ac.getBean("userDao");
//System.out.println(userDao);
//根据类型获取该对象
//如果该类型有两个实现类,会执行异常
//UserDao userDao=ac.getBean(UserDao.class);
//System.out.println(userDao);
//得到是id为userDao1的对象,类型为UserDao接口的实现类
UserDao userDao = ac.getBean("userDao2",UserDao.class);
System.out.println(userDao);

bean对象的范围和声明周期
springIOC容器默认是单例模式:单例模式的对象在创建容器时创建,销毁容器时销毁
scope:prototype 原型模式(多例模式):获取时创建,当对象长时间不再被引用,则被垃圾回收机制回收
scope:singleton:单例模式
scope:request:会话范围
scope:global session :全局范围 --spring 5的新特性中被删除

UserDao userDao1 =ac.getBean("userDao",UserDao.class);
System.out.pringln(userDao1);

UserDao userDao2=ac.getBean("userDao",UserDao.class);
System.out.println(userDao2);

实例化bean的三种方法

  • getBean(name)
  • 根据静态工厂获取对象
/**通过静态工厂获取对象*/
public class StaticFactory{
	public static UserDao getUserDao()
		return new UserDaoImpl();
		}
	}
<!-- 通过静态工厂创建UserDao对象-->
<!-- factory-method:工厂方法,返回UserDao对象的方法名-->
<bean id="userDao" class="com.ayyy.factory.StaticFactory" factory-method="getUserDao">
</bean>
  • 根据实例(非静态)工厂获取对象
/**实例工厂创建对象*/
public class InstanceFactory{
	public UserDao getUserDao(){
		return new UserDaoImpl();
		}
	}
	<!-- 创建实例工厂对象-->
	<bean id="instanceFactory" class="com.ayyy.factory.InstanceFactory" factory-method="getUserDao"></bean>

依赖注入

  • 什么是依赖注入
    业务层需要持久层的对象,在配置文件中给业务层传入持久层的对象,就是依赖注入

  • IOC
    控制反转包含了依赖注入和依赖查找

  • 构造方法注入

<!-- 依赖注入-->
		value 属性只能赋值简单的类型:基本数据类型和String类型
		ref: pojo类型,复杂类型,关联创建好的对象
		<!--默认创建对象方式,使用默认的空的构造方法创建对象-->
		<bean id="user" class="com.ayyy.domain.User">
			<!--<constructor-arg index="0" value="1"></constructor-arg>-->
        <!--<constructor-arg index="1" value="张三"></constructor-arg>-->
        <!--通过构造方法参数类型赋值-->
        <!--<constructor-arg type="java.lang.Integer" value="2"></constructor-arg>-->
        <!--<constructor-arg type="java.lang.String" value="李四"></constructor-arg>-->
        <!--通过构造方法参数名字赋值-->
        <constructor-arg name="id" value="3"></constructor-arg>
        <constructor-arg name="username" value="王五"></constructor-arg>
   			<constructor-arg name="sex" value="男"></constructor-arg>
        <constructor-arg name="birthday" ref="birthday"></constructor-arg>
    </bean>
	<bean id="birthday" class="java.util.Date"></bean>
  • set方法注入属性
<!--通过set方法注入-->
	<bean id="user2" class="com.ayyy.domain.User">
		<!--property :属性注入,先找到set方法,才能最终找到属性-->
		<property name="username" value="王朝"></property>
		<property name="birthday" ref="birthday"></property>
		<property name="sex" value="男"></property>
		<property name="id" value="4"></property>
	</bean>
  • p名称空间注入:基于set方法注入
    在头部文件中引入p名称空间
    使用p名称空间注入属性
	    <bean id="user3" class="com.ayyy.domain.User"
        p:id="5" p:username="马汉" p:sex="男" p:birthday-			ref="birthday"
        ></bean>

常用的注解

  • 配置文件:applicationContext.xml
   <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context
       http://www.springframework.org/schema/context/spring-context.xsd
        ">
    <!--
        开启注解,指定扫描的包 : context:component-scan
        引入context名称空间-引入约束
        base-package:指定要扫描的包, 扫描的是包及其子包
    -->
    <context:component-scan base-package="com.ayyy"></context:component-scan>
    <!--
                context:include-filter :指定包含过滤
                type="annotation": 按照类型过滤
                expression: 过滤的表达式
                    只扫描标记了Controller注解的类
        -->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"></context:include-filter>
        <!--
                context:exclude-filter:指定排除过滤
                type="annotation": 按照类型过滤
                expression:过滤的表达式
                        排除标记了Controller的注解都会扫描
        -->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</beans>
  • 在需要创建对象的类上添加注解
    @Component --标记在类上,不能用在方法上
    作用:创建对象,只要标记了,扫描了该包,对象就会创建衍生了三个子注解
    @Controller :一般用于web层(控制层)
    @Service :一般用于业务层
    @Repository :一般用于持久层
    相当于xml
<bean id="" class="全限类名"></bean>

属性:value=“userDao” 相当于xml的id=“userDao”
如果没有指定value属性,默认的名称是简单类名,首字母小写
UserDaoImpl --userDaoImpl

  • @Autowired --自动注入
    可以标记在属性和set方法上,如果标记在属性上,可以没有set方法
    特点:默认自动按照类型注入
    流程:当属性set方法标记了@Autowired,会自动在容器中查询该属性类型的对象,如果有且只有一个,则注入@Qualifiter:必须与@Aotuwored结合使用
    作用:如果自动注入按照类型注入失败,则按照指定的名称注入
    如果没有@Qualifiter,类型注入失败,则按照属性名称按照名称注入

  • @Resource --自动注入
    流程:当属性set方法标记了@Resource,会自动按照名称注入,如果名称没有找到,则根据类型注入,如果类型有多个,则抛出异常

  • @Autowired:默认按照类型注入,如果类型有多个,则按照名称注入–spring提供

  • @Resource:默认按照名称注入,没有名称没有找到,按照类型注入–jdk提供

  • @Configuration:标记该类为配置文件类
    可以替换applicationContext.xml

  • @ComponentSacn(“com.ayyy”)
    相当于:<context:component-scan base-package=“com.ayyy”>

  • @Import:引入其他配置文件

  • @Bean–通过方法创建对象,一般用于创建别人提供的类

  • @Scope(“singleton|prototype”)
    配置对象的范围:相当于:bean标签中的属性
    scope=“singleton|protptype”

  • 声明周期
    @PostConstruct:相当于bean标签的属性,init-method,指定初始化方法
    @PreDestroy:相当于bean标签的属性,destroy-method,指定对象的销毁方法

  • @Value给属性赋值–只能赋值简单类型
    PropertySource:引入外部属性文件
    相当于:<context:property-placeholder location=“classpath:jdbc.properties”></context:property-placeholder>
    Spring核心AOP
    什么是AOP
    AOP:全程是Aspect Oriented Programming即:面向切面编程
    简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强
    AOP的作用及优势
    作用:在程序运行期间,不修改源码对已有方法进行增强
    优势:减少重复代码,提高开发效率,维护方便
    AOP的实现
    使用动态代理
    动态代理的特点
    字节码随用随创建,随用随加载
    它与静态代理的区别也在于此,因为静态代理是字节码一上来就创建好,并完成加载,装饰者模式就是静态代理的一种体现
    动态代理常用的有两种方式
    基于接口的动态代理
    提供者:JDK官方的Proxy类
    要求:被代理类最少实现一个接口
    基于子类的动态代理
    提供者:第三方的CGLIB,如果报asmxxxx异常,需要导入asm.jar
    要求:被代理类不能用final修饰的类
    JDK官方的Proxy类创建代理对象

public interface IProxyProducer { 
 /** 
  * 销售商品   
  * @param money   
  */  
  	public void saleProduct(Float money);    
 /** 
  * 售后服务   
  * @param money   
  */  
  	public void afterService(Float money) ;
  	}
/** 
 * 一个生产厂家 
 */
  public class Producer implements IProxyProducer{   
 /** 
  * 销售商品   
  * @param money   
  */  
  public void saleProduct(Float money) {   
  	System.out.println("销售商品,金额是:"+money);  
  	} 
   /** 
  * 售后服务   
  * @param money   
  */  
  public void afterService(Float money) {   
  	System.out.println("提供售后服务,金额是:"+money);  
  		} 
  	} 


public class Consumer { 
 	public static void main(String[] args) {   
 		Producer producer = new Producer(); 
 		//  producer.saleProduct(5000f); 
		//  producer.afterService(1000f);      
	/** 
   * 动态代理:    
   *   特点:字节码随用随创建,随用随加载    
   *   分类:基于接口的动态代理,基于子类的动态代理    
   *   作用:不修改源码的基础上对方法增强    
   *   基于接口的动态代理:    
   *   提供者是:JDK 官方    
   *   使用要求:被代理类最少实现一个接口。    
   *   涉及的类:Proxy    
   *   创建代理对象的方法:newProxyInstance    
   *   方法的参数:    
   *    ClassLoader:类加载器。用于加载代理对象的字节码的。和被代理对象使用相同的类加载器。固定写法。    
   *    Class[]:字节码数组。用于给代理对象提供方法。和被代理对象具有相同的方法。和被代理对象实现相同的接口,就会具有相同的方法。固定写法    
   *    InvocationHanlder:要增强的方法。此处是一个接口,我们需要提供它的实现 类。通常写的是匿名内部类。    
   *          增强的代码谁用谁写。    
   * */ 
  IProxyProducer proxyProducer = (IProxyProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),      producer.getClass().getInterfaces(), new InvocationHandler() {      
  /** 
     * 执行被代理对象的任何方法都都会经过该方法,该方法有拦截的作用       
     * 参数的含义       
     *  Object proxy:代理对象的引用。一般不用       
     *  Method method:当前执行的方法       
     *  Object[] args:当前方法所需的参数       
     * 返回值的含义       
     *  和被代理对象的方法有相同的返回值       
     * */   
     
     @Override      
     	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {       
     			Object rtValue = null;        
      			//1.获取当前执行方法的钱       
      			Float money = (Float)args[0]; 
      			//2.判断当前方法是销售还是售后       
      			if("saleProduct".equals(method.getName())) {        
      			//销售        
      			rtValue = method.invoke(producer, money*0.75f);       
      			}       
      			if("afterService".equals(method.getName())) { 
       			//售后        
       			rtValue = method.invoke(producer, money*0.9f);       
       					}       
       			return rtValue;      
       				}     
       			}); 
     proxyProducer.saleProduct(8000f);   
     proxyProducer.afterService(1000f); 
 		} 
 }  

使用CGLIB的Enhancer类创建代理对象

还是那个演员的例子,只不过不让他实现接口。 
/** 
 * 一个生产厂家   
 */ 
 public class Producer{   
 /** 
 * 销售商品   
 * @param money   
  */  
  	public void saleProduct(Float money) {   
  	System.out.println("销售商品,金额是 cglib:"+money);  
  	}    
  /** 
 * 售后服务   
 * @param money   
  */  
  	public void afterService(Float money) {   
  	System.out.println("提供售后服务,金额是 cglib:"+money);  
  	}
 } 
 
 
/** 
 * 一个消费者   
 */ 
	public class Consumer { 
 
 	public static void main(String[] args) {   
        Producer producer = new Producer();      
        /** 
   		  * 动态代理:    
   		  *   特点:字节码随用随创建,随用随加载  
   		  *   分类:基于接口的动态代理,基于子类的动态代理    
   		  *   作用:不修改源码的基础上对方法增强    
   		  *   基于子类的动态代理    
   		  *   提供者是:第三方 cglib 包,在使用时需要先导包(maven 工程导入坐标即可)    
   		  *   使用要求:被代理类不能是最终类,不能被 final 修饰    
   		  *   涉及的类:Enhancer    
   		  *   创建代理对象的方法:create    
   		  *   方法的参数:    
   		  *    Class:字节码。被代理对象的字节码。可以创建被代理对象的子类,还可以获取 被代理对象的类加载器。    
   		  *    Callback:增强的代码。谁用谁写。通常都是写一个接口的实现类或者匿名内部 类。     
   		  *       我们在使用时一般都是使用 Callback 接口的子接口: MethodInterceptor   
   			*/   
        Producer cglibProducer = (Producer)Enhancer.create(producer.getClass(), new MethodInterceptor() {        
            /** 
    		  * 执行被代理对象的任何方法都会经过该方法     
    		  * 方法的参数:     
    		  *  前 3 个和基于接口中方法的参数含义一样。     
    		  *  MethodProxy methodProxy:当前执行方法的代理对象。     
    		  * 方法的返回值:     
    		  *  和被代理对象中方法有相同的返回值     
    		  */    
            @Override    
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {     
                Object rtValue = null;      
    			//1.获取当前执行方法的钱     
                Float money = (Float)args[0]; 
    			//2.判断当前方法是销售还是售后     
                if("saleProduct".equals(method.getName())) { 
     			//销售      
                    rtValue = method.invoke(producer, money*0.5f); 
   				 }     
                if("afterService".equals(method.getName())) { 
    			//售后      
                    rtValue = method.invoke(producer, money*0.8f);     
                }     
                return rtValue;    
            }  
  		}); 
     cglibProducer.saleProduct(8000f); 
  	 cglibProducer.afterService(1000f);  
    } 
}

AOP

  • Joinpoint(连接点):
    连接点就是指哪些被拦截到的点.在spring中,这些点指的是方法,因为spring只支持方法类型的连接点

  • Pointcut(切入点):
    切入点是指我们要对哪些Joinpoint进行拦截的定义

  • Advice(通知/增强)
    通知是指拦截到Joinpoint之后所要做的事情就是通知
    通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知

  • Introduction(引介)
    引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态的添加一些方法

  • Target(目标对象)
    代理的目标对象

  • Weaving(织入)
    是指把增强应用到目标对象来创建新的代理对象的过程
    spring采用动态代理织入,而AspectJ采用编译器织入和类装载期织入

  • Proxy(代理)
    一个类被AOP织入增强后,就产生一个结果代理类

  • Aspect(切面)
    是切入点和通知(引介)的结合

AOP的xml配置

  • 依赖
<!--引入spring的核心-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--引入spring的测试包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--引入单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!--配置aop,必须引入一个包:版本必须要1.8.7以上-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.9</version>
        </dependency>
  • 配置文件
<!--  
aop 的配置步骤:  第一步:把通知类的创建也交给 spring 来管理  
				第二步:使用 aop:config 标签开始 aop 的配置  
				第三步:使用 aop:aspect 标签开始配置切面,写在 aop:config 标签内部    id 属性:给切面提供一个唯一标识    ref 属性:用于引用通知 bean 的 id。  
				第四步:使用对应的标签在 aop:aspect 标签内部配置通知的类型    使用 aop:befored 标签配置前置通知,写在 aop:aspect 标签内部     method 属性:用于指定通知类中哪个方法是前置通知     pointcut 属性:用于指定切入点表达式。    
				切入点表达式写法:     关键字:execution(表达式)    表达式内容:     全匹配标准写法:      访问修饰符   返回值   包名.包名.包名...类名.方法名(参数列表)     例如:     public void com.ayyy.service.impl.AccountServiceImpl.saveAccount() --> 

<?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.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">
    <!--扫描表,创建bean对象-->
    <context:component-scan base-package="com.ayyy"></context:component-scan>

    <!--通知对象: 拦截到方法时,通知执行的对象-->
    <!--
        通知的类型
            前置通知: 方法之前执行
            后置通知: 方法执行完之后执行- 返回之前执行-如果有异常,则不执行
            最终通知: 方法执行完后总会执行- finally
            异常通知: 方法出现异常则执行
            环绕通知: 前置通知+后置通知+最终通知+异常通知
    -->
    <bean id="logger" class="com.ayyy.log.Logger"></bean>
    <!--配置aop-->
    <aop:config>
        <!--配置切面= 切入点 + 通知
            指定通知对象是谁
         -->
        <aop:aspect ref="logger">
            <!--配置切入点
                id:唯一的标志
                expression: 表达式

                * com.ayyy.service.impl.*.*(..)
                * com.ayyy.service..*.*(..)
                第一个*:代表方法任意返回值类型
                第二个*: 类名任意,impl包中所有的类
                第三个*: 任意方法名
                (..) : 参数任意,个数任意,类型任意,顺序任意
            其他的配置方式
                public void com.ayyy.service.impl.UserServiceImpl.findAll()
                void com.ayyy.service.impl.UserServiceImpl.findAll()
                * com.ayyy.service.impl.UserServiceImpl.findAll()
                * com.ayyy.service..UserServiceImpl.findAll() : .. 代表的是包,及其子包

            -->
            <aop:pointcut id="pointcut" expression="execution(* com.ayyy.service.impl.*.*(..))"></aop:pointcut>
            <!--织入: 告诉通知对象执行,具体执行哪一个方法-->
            <!--前置通知-->
            <!--<aop:before method="before" pointcut-ref="pointcut"></aop:before>-->
            <!--后置通知-->
            <!--<aop:after-returning method="afterReturning" pointcut-ref="pointcut"></aop:after-returning>-->
            <!--最终通知-->
            <!--<aop:after method="after" pointcut-ref="pointcut"></aop:after>-->
            <!--异常通知-->
            <!--<aop:after-throwing throwing="e" method="afterThrowing" pointcut-ref="pointcut"></aop:after-throwing>-->
			/** 
  			  * 环绕通知   
  			  * 问题:   
  			  * 当配置完环绕通知之后,没有业务层方法执行(切入点方法执行)   
  			  * 分析:   
  			  * 通过动态代理的代码分析,我们现在的环绕通知没有明确的切入点方法调用   
  			  * 解决:   
  			  * spring 框架为我们提供了一个接口,该接口可以作为环绕通知的方法参数来使用   
  			  * ProceedingJoinPoint。当环绕通知执行时,spring 框架会为我们注入该接口的实现类。   
  			  *它有一个方法 proceed(),就相当于 invoke,明确的业务层方法调用      
  			  *spring 的环绕通知:   
  			  *它是 spring 为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。   
  			  */  
  			  <!--环绕增强-->
            <aop:around method="around" pointcut-ref="pointcut"></aop:around>
        </aop:aspect>
    </aop:config>
</beans>

AOP的注解配置

package com.ayyy.log;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 *@Component: 创建类对象
 * @Aspect:配置该类为切面
 *  切面是:切入点 + 通知
 */
@Component
@Aspect
public class Logger {
    /**
     * 配置切入点
     */
    @Pointcut("execution(* com.ayyy.service.impl.*.*(..))")
    public void pointcut(){};


    /**
     *
     * @param joinPoint  连接点-- 拦截到的方法
     */
//    @Before("pointcut()")
    public void before(JoinPoint joinPoint){
        //被代理的对象
        Object target = joinPoint.getTarget();
        //拦截的类的名称
        String className = target.getClass().getName();
        System.out.println("拦截到的类名:" +className);
        //获取方法对象
        Signature signature = joinPoint.getSignature();
        //获取方法名
        String methodName = signature.getName();
        System.out.println("拦截到方法名:" + methodName);
        System.out.println("前置通知");
    }

//    @AfterReturning("pointcut()")
    public void afterReturning(){
        System.out.println("后置增强");
    }

//    @After("pointcut()")
    public void after(){
        System.out.println("最终增强");
    }

//    @AfterThrowing(value = "pointcut()",throwing = "e")
    public void afterThrowing(Exception e){
        System.out.println("执行的方法的异常:"+e);
        System.out.println("异常通知");
    }

    /**
     * ProceedingJoinPoint 可以执行拦截到方法的连接点对象
     * @param joinPoint
     */
    @Around("pointcut()")
    public void around(ProceedingJoinPoint joinPoint){
        try {
            System.out.println("前置通知");
            //执行原来的方法: 可以获取方法的返回值
            Object result = joinPoint.proceed();
            System.out.println("后置增强");
        } catch (Throwable e) {
            System.out.println("异常通知");
//            e.printStackTrace();
        } finally {
            System.out.println("最终增强");
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值