当前位置: 首页 > news >正文

沈阳网站建设 南塔广东省最新新闻

沈阳网站建设 南塔,广东省最新新闻,线上网站开发系统流程,建造师免费自学网站提示:英语很重要,单词是读的,是拼出来的,和拼音一样 文章目录 前言前期准备1️⃣ DI 依赖注入1、xml 配置方式2、注解方式 annotation❗相关注解Spring中Bean的作用域❗Scope() 注解Qualifier("XXXServiceImpl") 指定哪…

提示:英语很重要,单词是读的,是拼出来的,和拼音一样

文章目录

  • 前言
  • 前期准备
  • 1️⃣ DI 依赖注入
    • 1、xml 配置方式
    • 2、注解方式 annotation❗
      • 相关注解
      • Spring中Bean的作用域❗
      • @Scope() 注解
      • @Qualifier("XXXServiceImpl") 指定哪个实现类
    • 3、javaConfig方式
    • BeanFactory与ApplicationContext的区别是?❗
  • 2️⃣ AOP 面向对象
    • 一、JDK 动态代理
    • 二、Cglib 字节码生成
    • 抽取重复代码
      • 总结
    • 五种通知类型
    • 性能监测案例


前言

提示:controller→service→dao互相依赖

Spring容器最大的作用:

  1. 帮我们管理很多类对象的创建
  2. 帮我们管理他们对象之间的彼此依赖注入

Spring实现依赖注入有三种方式:注解方式(官方推荐方式)、xml配置文件方式、javaConfig方式。

Spring两大核心
DI:依赖注入(Dependency Injection) AOP:面向切面编程(Aspect Oriented Programming)

Spring框架的优点如下

  1. 非侵入式设计,最小化应用程序代码对框架的依赖。
  2. 解耦、简化开发,降低组件之间的耦合性。
  3. 支持AOP,提高程序的复用性。
  4. 支持声明式事务处理,方便管理事务。
  5. 方便程序测试,提供对Junit4的支持。
  6. 方便集成各种优秀框架,如Struts、Hibernate、MyBatis、Quartz等。
  7. 简化Java EE API的使用,提供对JDBC、JavaMail等API的封装,降低应用难度。

提示:以下是本篇文章正文内容,下面案例可供参考

前期准备

第一步:新建项目Maven项目
在这里插入图片描述
在下一步中勾选第一个选项,创建一个简单的项目,最后填写相关信息后完成
在这里插入图片描述
第二步:完善 pom.xml 文件

项目建成后在 pom.xml 文件中导入相关代码,比如:

缺什么加什么

  <dependencies><!-- 此依赖会关联引用Spring中的所有基础jar包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.8.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.7</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.15</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency></dependencies>

第三步:配置 main/resources 文件夹

  1. bean.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.1.xsd"></beans>
  1. log4j.properties配置文件,可以显示 log 输出
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %m%n
log4j.rootLogger=debug,stdout

第四步:接下来新建测试类

package com.spring;import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class AppTestUnit
{ApplicationContext context = null;@Beforepublic void before() throws Exception {// xml配置文件方式实现                                                          配置文件的路径context = new  ClassPathXmlApplicationContext("bean.xml");// 注解方式实现,包名被更改时,这里对应的包名也要改//context = new  AnnotationConfigApplicationContext("com.spring");}@Test public void test() {}}

1️⃣ DI 依赖注入

原来是叫 IOC(Spring 的Bean中主要包含三种装配方式)

依赖注入的原理:
将对象的依赖关系从代码中移除,而是通过外部容器来管理这些依赖关系,将某一个需要的依赖,右容器注入

1、xml 配置方式

大致过程:

  1. dao(接口和实现类、配置xml、测试)
  2. service(接口和实现类、配置xml、测试)
  3. controller(直接写类、配置xml、测试)

在main/java文件夹下新建包:com.spring.xml,然后在下面新建dao、service、controller包

dao 包下新建接口:这里以 Goods 商品 取名

在里面加上一个方法

public interface GoodsDao![请添加图片描述](https://img-blog.csdnimg.cn/aca00a926a4c4e7998e6caf4a0d8ac8b.png){void insertGoods();
}

紧接着着这个包下创建一个同名+Impl的实现类

项目创建好后,在实现类后面跟上implements+要实现的接口名,然后保存添加未实现的方法
请添加图片描述
在里面加一句输出,代表执行了

	@Overridepublic void insertGoods() {System.out.println("成功向MySQL数据库中增加一行商品数据");}

接下来需要在bean.xml文件中进行一个配置,因为 dao 类对象要容器创建

<!-- 在xml中进行配置,配置好的类的对象创建 就由spring容器负责 --> <!-- 实现类创建对象 -->
<bean id="goodsdao" class="com.spring.xml.dao.GoodsDaoImpl"></bean>
<!-- id="dao包接口名" class="实现类的限定名" -->

测试代码:传名字
getBean后的值是刚才在bean.xml中配置的id值 goodsdao,然后加强转(有一个向下的转型)
在这里插入图片描述

	@Test public void test() {// 从容器context中获得getBean使用的对象GoodsDaoImpl dao = (GoodsDaoImpl) context.getBean("goodsdao");dao.insertGoods();		}

测试运行:
在这里插入图片描述

getBean还有另一个重载的方法:传类的信息(常用)

两种实现方法结果一致

	@Test public void test() {// 从容器context中获得getBean使用的对象
//		GoodsDaoImpl dao = (GoodsDaoImpl) context.getBean("goodsdao");GoodsDaoImpl dao = context.getBean(GoodsDaoImpl.class);dao.insertGoods();		}

接下来写 service 包,在里面写个接口

public interface GoodsService {void addGoods();
}

再写一个实现类,与 service 包接口同名+Impl
第一步:添加未实现的方法
第二步:定义 dao 类型的变量(体现业务依赖 dao )
第三步:加set方法只有xmljavaConfig需要
在这里插入图片描述
XyzServiceImpl 代码:

public class GoodsServiceImpl implements GoodsService{//2、添加dao类型的变量(体现业务依赖dao)private GoodsDao dao;// 完成需要的dao对象的注入public void setDao(GoodsDao dao) {this.dao = dao;}// 3、加set方法只有xml和javaConfig需要@Overridepublic void addGoods() {  // 1、添加未实现的方法	// 4、输出System.out.println("商品业务——addGoods");// 业务类调 daodao.insertGoods();}
}

现在ServiceImpl 实现类写完了,因为业务类对象也要容器创建,所以接下来在bean.xml内加上容器

property标记代表所需依赖注入的配置

property 中的 name 属性名指的是ServiceImpl 实现类中添加dao类型的变量

property 中的 ref 属性指的是要注入的对象 id
请添加图片描述

<!-- id="小写service包接口名" class="实现类的限定名" -->
<bean id="goodsservice" class="com.springtest.service.GoodsServiceImpl">
<!-- service需要dao注入进来,property标记代表所需依赖注入的配置-->
<property name="dao" ref="goodsdao"></property>
</bean>

回到测试类写service测试,先注释或删掉dao的测试

	@Test public void test() {// 从容器context中获得getBean使用的对象
//		GoodsDaoImpl dao = (GoodsDaoImpl) context.getBean("goodsdao");
//		GoodsDaoImpl dao = context.getBean(GoodsDaoImpl.class);
//		dao.insertGoods();		GoodsServiceImpl service = context.getBean(GoodsServiceImpl.class);// 证明依赖注入成功:调service方法时,dao的方法也输出了service.addGoods();}

在这里插入图片描述
最后写controller

public class GoodsController {// 2.增加接口体现依赖private GoodsService service;// 3.生成set方法public void setService(GoodsService service) {this.service = service;}
// 1.doGet()public void doGet() {System.out.println("获取请求数据");// 4.调用service方法service.addGoods();System.out.println("生成相应");}
}

接下来写controller的bean.xml配置
在这里插入图片描述

<!-- id="小写controller类名" class="Controller类的限定名" -->
<bean id="goodscontroller" class="com.springtest.controller.GoodsController">
<property name="service" ref="goodsservice"></property>
</bean>

controller测试:先注释或删掉 dao 和 service 的测试

	@Test public void test() {// 从容器context中获得getBean使用的对象
//		GoodsDaoImpl dao = (GoodsDaoImpl) context.getBean("goodsdao");
//		GoodsDaoImpl dao = context.getBean(GoodsDaoImpl.class);
//		dao.insertGoods();		//		GoodsServiceImpl service = context.getBean(GoodsServiceImpl.class);
//		// 证明依赖注入成功:调service方法时,dao的方法也输出了
//		service.addGoods();GoodsController controller = context.getBean(GoodsController.class);controller.doGet();}

在这里插入图片描述

2、注解方式 annotation❗

注解:

  1. 依赖创建对象:@Component(通用)
  2. 依赖注入注解:@Autowired

在main/java文件夹下新建包:com.spring.annotation,然后在下面新建dao、service、controller包

先在dao包下新建接口和接口的实现类,这里取名 business

接口代码:

public interface BusinessDao {void updateBusiness();
}

接口的实现类:

// 注解功能等同于xml中的bean标记  abc是自定义名字
@Component
public class BusinessDaoImpl implements BusinessDao{@Overridepublic void updateBusiness() {// 添加未实现的方法System.out.println("修改商家数据");}}

测试代码:

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class AppTestAnnotation
{ApplicationContext context = null;@Beforepublic void before() throws Exception {
// 这里配置的包名,当包名被改变时,这里也需要被改变context = new  AnnotationConfigApplicationContext("com.spring");// 创建注解容器时,需要指定扫描的包名// 那么容器创建时会自动的扫描这个包以及子包中的所有类// 找有Component注解的类}@Test public void test() {}
}

接下来写注解Test 的内容,看数据能否被取出

	@Test public void test() {BusinessDaoImpl dao = context.getBean(BusinessDaoImpl.class);dao.updateBusiness();}

在这里插入图片描述
在BusinessDaoImpl实现类的注解中可以加上自定义名字:@Component("abc")
在这里插入图片描述

接下来在service中新建接口以及接口对应的实现类

接口代码:

public interface BusinessService {void update();
}

接口对应的实现类:

// 3.添加注解
@Component 
public class BusinessServiceImpl implements BusinessService{// 4.自定装配实现依赖注入@Autowired   // 2.增加dao类型的属性(接口)private BusinessDao dao;@Overridepublic void update() {// 1.添加未实现的方法// 5.输出  调用依赖dao的方法System.out.println("修改业务");dao.updateBusiness();}}

在测试类中写service测试:先注释或删掉掉dao的测试

	@Test public void test() {BusinessServiceImpl service = context.getBean(BusinessServiceImpl.class);service.update();}

在这里插入图片描述
接下来在controller包中新建controller类

@Component  // 2.加注解
public class BusinessController {@Autowired  // 3.依赖注入注解  自动装配private BusinessService service;   // 1.加依赖的属性(接口)// 4.加方法public void doPost() {System.out.println("获取请求数据");service.update();System.out.println("生成响应");}}

测试类测试:

	@Test public void test() {BusinessController controller = context.getBean(BusinessController.class);controller.doPost();}

在这里插入图片描述

相关注解

上面案例说了两个注解:

  1. 依赖创建对象:@Component(通用)
  2. 依赖注入注解:@Autowired

下面还有三个注解,这三个注解功能一样,但更有语义化

将一个类声明为Spring容器管理的bean的注解有:

@Component通用的注解,可标注任意类为 Spring 组件。如果一个Bean不知道属于哪个层,可以使用

@Repository:对应数据层即 Dao 层,主要用于数据库相关操作。整合mybatis时,用 @Mapper

@Service:对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao层。

@Controller:对应 Spring MVC控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。

如果把上面案例中的 dao 层中的 @Component 注解换为:@Repository
service 中的 @Component 注解换为:@Service
controller 中的 @Component 注解换为:@Controller

那么测试输出一样,也就是说:

Spring中Bean的作用域❗

Spring中Bean的作用域及各自意义

@Scope() 注解:设置Bean的作用域。值如下:

作用域说明
singleton单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例
prototype原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例
request对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效
session对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
globalsession每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效

@Scope() 注解

在累的前面加上@Scope()

@Component
@Scope("prototype")   //每次都是一个新对象
public class Hello {}

测试代码:默认应该是单例

	@Test public void test() {// 为了测试每次取出的都是同一个对象for(int i=0; i<10;i++) {Hello s = context.getBean(Hello.class);System.out.println(s);}		}

输出信息:
请添加图片描述

@Qualifier(“XXXServiceImpl”) 指定哪个实现类

在service包中新建实现类BusinessServiceImpl1,让他也实现BusinessService接口

@Service
public class BusinessServiceImpl1 implements BusinessService{@Overridepublic void update() {// TODO 自动生成的方法存根System.out.println("asdfg");}}

现在有两个实现类对象存在

测试类代码执行:

	@Test public void test() {BusinessController controller = context.getBean(BusinessController.class);controller.doPost();	}

报错信息:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.spring.annotation.service.BusinessService' available: expected single matching bean but found 2: businessServiceImpl,businessServiceImpl1at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:220)at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1285)at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227)at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)... 37 more

原因:期望一个匹配对象,但是现在有两个businessServiceImpl和businessServiceImpl1

在BusinessController 类中加一个@Qualifier注解,让他指定哪个实现类
在这里插入图片描述
输出结果:
在这里插入图片描述

3、javaConfig方式

  1. 在项目初期时,会做一些项目配置
  2. 某个类不是我们能更改的代码,但是这个类还需要容器管理对象的时候加 javaConfig
  3. javaconfig方式必须给配置类增加@Configuration注解

在main/java文件夹下新建包:com.spring.javaconfig,然后在下面新建dao、service包

dao 包下新建接口及同名的接口+Impl实现类

接口中代码:

public interface UserDao {void query();
}

实现类代码:

public class UserDaoImpl implements UserDao{@Overridepublic void query() {// TODO 自动生成的方法存根System.out.println("查询用户数据");}}

在com.spring.javaconfig 包下新建类 AppConfig,里面暂时放 dao 的方法

@Configuration   // javaconfig方式必须给配置类增加此注解
public class AppConfig {@Bean    // 有Bean注解的方法,它返回的对象就会交由spring容器管理public UserDaoImpl dao() {return new UserDaoImpl();}}

测试类:

	@Test public void test() {UserDaoImpl dao = context.getBean(UserDaoImpl.class);dao.query();}

在这里插入图片描述
新建service接口及其实现类

接口代码:

public interface UserService {void query();
}

接口实现类:

public class UserServiceImpl implements UserService{// Service依赖Daoprivate UserDao dao;public void setDao(UserDao dao) {// set方法单独生成this.dao = dao;}@Overridepublic void query() {// TODO 自动生成的方法存根System.out.println("查询用户业务");dao.query();}}

在AppConfig 类里面再加一个service方法:

@Bean// 可以接口/实现类public UserService service(UserDao dao) {UserServiceImpl service = new UserServiceImpl();service.setDao(dao);return service;}

测试代码:

	@Test public void test() {UserServiceImpl service = context.getBean(UserServiceImpl.class);service.query();}

在这里插入图片描述

BeanFactory与ApplicationContext的区别是?❗

BeanFactory:
Bean工厂(org.springframework.beans.factory.BeanFactory)是Spring框架最核心的接口,提供了IoC的配置机制,使管理不同类型的Java对象成为可能。特点是:采用延迟加载Bean,直到第一次使用Bean实例时才会创建Bean。

ApplicationContext:
应用上下文(org.springframework.context.ApplicationContext),继承自BeanFactory,提供了更多面向应用的功能,比如国际化支持、框架事件体系,更易于创建实际应用。

2️⃣ AOP 面向对象

简单的说它就是把我们程序重复的代码抽取出来
在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。

应用场景:记录日志、监控方法运行时间 (监控性能)、权限控制、缓存优化 、事务管理

AOP 内注解:
@Pointcut:定义切点,指定在哪些方法或类上应用增强。

@Before:在目标方法执行之前执行增强。

@AfterReturning:在目标方法正常返回后执行增强。

@AfterThrowing:在目标方法抛出异常后执行增强。

@Around:在目标方法执行前后执行增强。

@DeclareParents:为被切入对象引入新的接口和实现类。

两种AOP实现方案:JDK 动态代理、Cglib 字节码生成

一、JDK 动态代理

  1. 运用方式

在使用JDK动态代理时,需要实现InvocationHandler接口,并在方法中实现代理逻辑,同时利用Proxy类生成代理对象。下面是一个简单的实现示例:

public interface HelloWorld {void sayHello();
}public class HelloWorldImpl implements HelloWorld {@Overridepublic void sayHello() {System.out.println("Hello World!");}
}public class MyInvocationHandler implements InvocationHandler {private Object target;public MyInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before method:" + method.getName());Object result = method.invoke(target, args);System.out.println("After method:" + method.getName());return result;}
}public class Main {public static void main(String[] args) {HelloWorld helloWorld = new HelloWorldImpl();MyInvocationHandler handler = new MyInvocationHandler(helloWorld);HelloWorld proxyInstance = (HelloWorld) Proxy.newProxyInstance(helloWorld.getClass().getClassLoader(),helloWorld.getClass().getInterfaces(), handler);proxyInstance.sayHello();}
}
  1. 何时使用

JDK动态代理适用于对实现了接口的对象进行代理,它的运行时效率相对较高、实现较为简单,适用于大部分场景下的对象代理。

  1. 适用场景
  • 对实现了接口的对象进行代理;
  • 需要在运行时动态生成代理类;
  • 对于单继承模型较为适用。
  1. 优缺点

JDK动态代理的优势在于:

  • 运行时效率相对较高;
  • 实现较为简单。

缺点在于:

  • 只能代理实现了接口的对象。

二、Cglib 字节码生成

  1. 运用方式

在使用Cglib字节码生成时,需要引入Cglib的依赖,继承MethodInterceptor接口,并在方法中实现代理逻辑。下面是一个简单的实现示例:

public interface HelloWorld {void sayHello();
}public class HelloWorldImpl {public void sayHello() {System.out.println("Hello World!");}
}public class MyMethodInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("Before method:" + method.getName());Object result = methodProxy.invokeSuper(o, objects);System.out.println("After method:" + method.getName());return result;}
}public class Main {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(HelloWorldImpl.class);enhancer.setCallback(new MyMethodInterceptor());HelloWorldImpl proxy = (HelloWorldImpl) enhancer.create();proxy.sayHello();}
}
  1. 何时使用

Cglib 字节码生成适用于对未实现接口的对象进行代理,代理逻辑灵活,适用于复杂逻辑下的对象代理。

  1. 适用场景
  • 对未实现接口的对象进行代理;
  • 需要在运行时动态生成代理类;
  • 对于单继承模型较为适用。
  1. 优缺点

Cglib 字节码生成的优势在于:

  • 代理逻辑的灵活性,可以代理未实现接口的对象。

缺点在于:

  • 运行时效率相对较低;
  • 实现复杂。

三、JDK 动态代理和 Cglib 字节码生成的比较

JDK动态代理和Cglib字节码生成都是Java中常用的实现动态代理的方式,它们各自之间的优缺点如下:

JDK动态代理的优点在于运行时效率相对较高、实现较为简单;缺点在于只能代理实现了接口的对象。

Cglib字节码生成的优点在于代理逻辑的灵活性,可以代理未实现接口的对象;缺点在于运行时效率相对较低、实现复杂。

在使用 JDK动态代理和Cglib字节码生成时,需要根据具体对象的特点及使用场景来决定使用哪种方式。对于实现了接口的对象,可以优先考虑使用JDK动态代理,因为它的运行时效率相对较高、实现较为简单;对于未实现接口的对象,可以优先考虑使用Cglib字节码生成,因为它代理逻辑灵活,可以代理未实现接口的对象。


抽取重复代码

AOP核心思想把重复的代码从方法中抽取出来

在main/java文件夹下新建包:com.spring.aop,然后在下面新建aop、service包

先在service包内增加代码,创建接口及其实现类

public interface FoodService {void insert();void delete();
}

实现类代码:在开始执行前的输出视为重复代码

@Service
public class FoodServiceImpl implements FoodService{@Overridepublic void insert() {// 添加未实现的方法System.out.println("insert方法开始执行");// 模拟调用dao层代码System.out.println("增加业务代码");}@Overridepublic void delete() {// 添加未实现的方法System.out.println("delete方法开始执行");// 模拟调用dao层代码System.out.println("删除业务代码");}}

测试代码:

	@Test public void test() {FoodServiceImpl service = context.getBean(FoodServiceImpl.class);service.insert();service.delete();}

在这里插入图片描述
因为方法中有重复代码,这时候适用于AOP,接下来定义一个切面代码

在aop包内新建类MyAspect,并把之前的重复代码注释或删掉

//基本语法
@Component
@Aspect  // 方面 切面
@EnableAspectJAutoProxy  //开启切面动态代理
public class MyAspect {// 切入点 配置的是切入执行的方法信息    execution是函数,后面加(),如果包名改变这里也需要改@Pointcut("execution(* com.spring.serve.*.*(..))")// 第一个*:所切入执行方法的返回值类型(这里不区分返回值类型),这个方法所在的类的信息:完整的限定名// 第二个*:切入到serve包所有类的方法// 第三个*:切入到哪些方法// (..):方法中的所有参数public void pt() {}// 抽取出来的重复代码,封装到方面中的一个通知,把之前的重复代码注释或删掉// 通知抽取方法@Before("pt()")   //通知和切入点的联系public void before(JoinPoint jp) {// JoinPoint 连接点,代表aop切入的方法信息String methodName = jp.getSignature().getName();System.out.println(methodName+"业务开始执行");}
}

测试类代码:
因为他会动态生成一个新的类,所以更改测试代码(改接口)

	@Test public void test() {FoodService service = context.getBean(FoodService.class);service.insert();service.delete();}

请添加图片描述


总结

一、定义一个切面/方面类

二、增加两种类型的方法:

  1. 通知(抽取出来的方法信息,重读代码,加注解@Before("xxx()")
  2. 定义切入点的方法

三、AOP中的切入点

// 切入点 配置的是切入执行的方法信息    execution是函数,后面加(),如果包名改变这里也需要改@Pointcut("execution(* com.spring.serve.*.*(..))")// 第一个*:所切入执行方法的返回值类型(这里不区分返回值类型),这个方法所在的类的信息:完整的限定名// 第二个*:切入到serve包所有类的方法// 第三个*:切入到哪些方法,这里是所有方法// (..):方法中的所有参数

接下来在通知的方法中加一个参数,从参数里面拿到切入方法的相关信息

	public void pt() {}// 抽取出来的重复代码,封装到方面中的一个通知,把之前的重复代码注释或删掉// 通知抽取方法@Before("pt()")   //通知和切入点的联系public void before(JoinPoint jp) {// JoinPoint 连接点,代表aop切入的方法信息String methodName = jp.getSignature().getName();System.out.println(methodName+"业务开始执行");}
}

在这里插入图片描述

五种通知类型

方面代码一般也称为通知:定义一个“切面”要实现的功能。通知有五种:

  1. 前置通知@Before:在某连接点(JoinPoint 就是要织入的业务方法)之前执行的通知。
  2. 后置通知@After:当某连接点退出时执行的通知(不论是正常结束还是发生异常)。
  3. 返回通知@AfterReturning:(最终通知)在这里可以得到业务方法的返回值。但在发生异常时无法得到返回值。
  4. 环绕通知@Around:包围一个连接点的通知,也就是在业务方法执行前和执行后执行的通知。
  5. 异常通知@AfterThrowing:在业务方法发生异常时执行的通知。

后置通知:

	@After("pt()")public void after() {System.out.println("后置通知执行了");}

测试输出后:在最后面输出了——后置通知执行了

返回通知:

	@AfterReturning("pt()")public void afterReturn() {System.out.println("返回通知执行了");}

在service接口文件中给他加一个带返回值的方法

int update();

然后在service接口实现类中添加方法

	@Overridepublic int update() {// TODO 自动生成的方法存根System.out.println("修改业务");return 0;}

在测试类中加上修改方法并注释掉之前的方法(因为没有返回值)

	@Test public void test() {FoodService service = context.getBean(FoodService.class);
//		service.insert();
//		service.delete();service.update();}

让他发生异常就不会执行了

	@Overridepublic int update() {// TODO 自动生成的方法存根System.out.println("修改业务");String string = null;string.length();return 0;}

发生空指针异常

接下来还是在MyAspect类中写异常通知:

	@AfterThrowing("pt()")public void AfterThrowingException() {System.out.println("异常通知执行了");}

把前面长度length那一行注释掉再运行:修改业务输出

环绕通知:

@Around("pt()")				   public Object around(ProceedingJoinPoint jp) {System.out.println("环绕通知--1执行了");Object object = null;// 切入的方法执行try {object = jp.proceed();} catch (Throwable e) {// TODO 自动生成的 catch 块e.printStackTrace();}System.out.println("环绕通知--2执行了");return object;}

请添加图片描述

性能监测案例

@Component
@Aspect
@EnableAspectJAutoProxy
public class PerformanceAspect {@Pointcut("execution(* com.spring.serve.*.*(..))")public void cut() {}@Around("cut()")public Object executedTime(ProceedingJoinPoint jp) {long begin = System.currentTimeMillis();Object object = null;try {object = jp.proceed();} catch (Throwable e) {// TODO 自动生成的 catch 块e.printStackTrace();}long end = System.currentTimeMillis();String methodName = jp.getSignature().getName();System.out.println(methodName+"方法执行共花费"+(end-begin)+"毫秒");return object;}
}

测试运行后:

	@Test public void test() {FoodService service = context.getBean(FoodService.class);service.update();}

在这里插入图片描述
因为方法很小,执行时间很短,所有看不出来

接下来在接口实现类中改造update方法,人为加个休眠

@Overridepublic int update() {// TODO 自动生成的方法存根System.out.println("修改业务");String string = null;//string.length();try {// 随机数Thread.sleep(new Random().nextInt(1000));} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}return 0;}

再次运行:
在这里插入图片描述


http://www.dinnco.com/news/27475.html

相关文章:

  • php网站管理旅游seo整站优化
  • 做网站套路线上职业技能培训平台
  • 视频网站做电商搜索引擎优化免费
  • 网站换服务器有影响吗对seo的理解
  • 做网站页面设计报价新乡seo网络推广费用
  • 做电影网站考什么产品软文怎么写
  • 英文网站建站公司磁力棒
  • 给公司做网站需要什么信息济源网络推广
  • 龙岗网站价格今日国际新闻最新消息大事
  • wordpress外网端口西安seo站内优化
  • 武汉网站优化价格seo关键词排名优化制作
  • 哪些网站用python做服务框架百度seo排名软件
  • 注册的空间网站吗优化关键词排名的工具
  • wordpress 交流站长工具seo综合查询工具
  • 网站如何做线上和线下推广最近新闻今日头条
  • wordpress tags插件电脑系统优化软件
  • 秦皇岛网站建公司百度首页
  • 网站服务器管理 硬件网站排行查询
  • 上海网站建设网页制作网站品牌推广策略
  • 网络推广服务营销北京seo全网营销
  • 廊坊seo软件昆明seo网站管理
  • 想注册一个做网站的公司网站服务器速度对seo有什么影响
  • 免费做h5的网站网站排名优化软件联系方式
  • hbuilder 做网站国际新闻今日头条
  • 郑州网站建设电话网站建设哪家好公司
  • 阿里云官网入口seo外贸网站制作
  • 网站建设维护 天博网络下载百度语音导航地图
  • b2c电商网站开发百度自动搜索关键词软件
  • 动漫设计与制作学费北京优化互联网公司
  • 建设网站的意义收录优美图片崩了