用到的注解
@Component
- @Component是Spring框架中的核心注解之一,它用于标识一个类为Spring容器的一个组件
- 使得该类可以被Spring自动扫描并纳入管理。
- 在使用@Component注解时,可以指定该组件的名称,也可以让Spring自动生成一个默认名称。 默认名称是首字母是小写的类名(如: Book 则id就是book)
- 每个组件都会被当作一个Bean对象,被纳入到Spring容器中进行管理。
@ComponentScan(basePackages={“com.hyp.Spring.Aspect”})
- 组件查找 用于指示Spring容器应该扫描那些包以查找组件
@EnableAspectJAutoProxy(proxyTargetClass = true)
- @EnableAspectJAutoProxy是Spring框架中的注解,用于开启基于AspectJ的切面自动代理。
- 通过在配置类上添加@EnableAspectJAutoProxy注解, 可以使得Spring框架自动为被@Aspect注解所标记的切面类创建代理对象,并将这些代理对象添加到Spring容器中供其他组件使用。
- @EnableAspectJAutoProxy注解支持一个名为proxyTargetClass的属性,用于指定切面代理的类型。
- 当该属性值为true时,代理对象基于类进行创建;当该属性值为false时,代理对象基于接口进行创建。默认情况下,该属性值为false
@Order(1)
- 用于指定Bean对象在同一类型的多个Bean对象中的加载顺序
- 数值越小的Bean对象将会越早被加载
@Acpect
- 声明这是一个切面类,并创建这个类的代理对象,交给Spring容器
- 使用此注解需要在配置文件中配置
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
注意: 即使没有配置上述代码,方法也可以实现增强是为什么呢?
这是因为:
当 <aop:aspectj-autoproxy> 元素缺失时,
默认启用的是基于代理的 AOP,因此即使没有显式地配置 <aop:aspectj-autoproxy>,
仍然可以实现增强。但是如果你使用的是 AspectJ 特定的语法,
如 @DeclareParents 和 @DeclareErrorRendering 等,
则必须使用 <aop:aspectj-autoproxy> 启用 AspectJ 模式。
因此,建议在使用 @Aspect 注解的同时,显式地在 Spring 配置文件中配置 < aop:aspectj-autoproxy>
元素以启用 AOP 功能。
使用AOP
在使用AOP时,有两种方式
- xml配置文件配置【bean.xml】
- 完全注解开发【Annotation(注解)】
使用配置文件开发
使用xml文件配置增强类(不使用注解)
AcpectJ.xml:
使用xml配置文件进行配置时,需要创建被增强类和增强类的bean对象
并且需要配置aop
<!--先创建增q类和被增强类的bean对象-->
<!--被增强类-->
<bean id="user" class="com.hyp.Spring.Aspect.User.User"></bean>
<!--增强类-->
<bean id="userProxy" class="com.hyp.Spring.Aspect.User.UserProxy"></bean>
<!--配置aop增强-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="cut" expression="execution(* com.hyp.Spring.Aspect.User.User.say(..))"/>
<!--配置切面 使用的是前置通知 -->
<aop:aspect ref="userProxy">
<aop:before method="before" pointcut-ref="cut"></aop:before>
</aop:aspect>
</aop:config>
Java代码
测试代码
/**
* 被增强类
*/
public class User{
/*切点*/
public void say() {
System.out.println("人说话~~");
}
}
/**
* 增强类
*/
public class UserProxy {
/*通知*/
public void before(){
System.out.println("前置通知");
}
}
/**
测试类
**/
public class textAop{
@Test
public void testBeforeByConfigFile(){
ApplicationContext context = new ClassPathXmlApplicationContext("AspectJ.xml");
//使用getBean()方法获取User对象,
User user = context.getBean("user",User.class);
user.say();
}
}
测试结果
使用注解开发
bean.xml
需要在bean.xml文件中打开注解扫描,并且开启Aspect自动生成代理对象
<!--开启组件扫描 使用注解时使用
base-package属性是定义在某个包之下开启注解扫描-->
<context:component-scan base-package="com.hyp.Spring.Aspect"></context:component-scan>
<!--开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- 这段XML代码是使用Spring AOP时开启Aspect生成代理对象的配置。它使用了aop:aspectj-autoproxy标签,指示Spring启用AspectJ的自动代理功能。在类上加注@Acpect注解,并在xml文件中开启Acpect生成代理对象。
- 在Spring AOP中,开启自动代理(autoproxy)可以让Spring根据切点表达式自动生成代理对象,并在方法调用前、后或抛出异常时织入相应的增强处理逻辑,从而实现横切关注点的功能。
- 如果不开启自动代理,则需要手动配置每个切面,并将其作为bean添加到Spring应用程序上下文中。使用自动代理更加方便和灵活,可以简化Spring应用程序中AOP的配置和管理。
bean.xml
需要在bean.xml文件中打开注解扫描
<!--开启组件扫描 使用注解时使用-->
<context:component-scan base-package="com.hyp.Spring.Aspect"></context:component-scan>
增强类
@Component//创建增强类对象 用于标识一个类为Spring容器的一个组件,使得该类可以被Spring自动扫描并纳入管理
@Aspect //声明这是一个切面类,并创建这个类的代理对象,交给Spring容器
@Order(2)//设置增强类的优先级
public class BookProxy {
/**
* 切入点方法
*/
/*给一个切入点增强多个功能时,每一个都要指定切入点,每个个都要写切入点表达式
相 当繁琐可以使用@Pointcut注解,进行相同切入点的抽取*/
@Pointcut(value = "execution(* com.hyp.Spring.Aspect.Book.addBook(..))")
public void pointCut() {
}
/**
* 使用Before注解
* 设置方法的前置通知
* 使用切面表达式("execution=(* com.hyp.Spring.Aspect.Book.addBook(.))")
* 设置这个前置通知的 切点
*/
@Before(value = "execution(* com.hyp.Spring.Aspect.Book.addBook(..))")
//使用相同切入点函数(必须抽取相同切入点)
public void before() {
System.out.println("前置通知");
}
/*
最终通知,
不论程序怎么样执行都会执行
使用切入点方法pointCut()
*/
@After(value = "pointCut()")
public void after() {
System.out.println("最终通知");
}
/*遇到异常的话,不会执行*/
@AfterReturning(value = "execution(* com.hyp.Spring.Aspect.Book.addBook(..))")
public void AfterReturning() {
System.out.println("afterRetuning,后置通知(也被称为返回通知)");
}
/*异常通知,程序出现异常的话,执行
* 没有异常,不执行*/
@AfterThrowing(value = "execution(* com.hyp.Spring.Aspect.Book.addBook(..))")
public void afterThrowing() {
System.out.println("afterThrowing 异常通知");
}
/*环绕通知,*/
@Around(value = "execution(* com.hyp.Spring.Aspect.Book.addBook(..))")
public void Around(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕通知前");
point.proceed();
System.out.println("环绕通知后");
}
}
测试类:
@Test
public void testBookProxy(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//因为Book对象使用了@Component注解,
// Spring容器自动为这个类创建了一个bean对象,将id自动设置为首字母为小写的类名
//getBean(String id , Class class) ,id 是bean对象的id
Book book = context.getBean("book", Book.class);
book.addBook("java核心技术");
}
被增强类
/**
* 被增强类Book
* 因为Book对象使用了@Component注解,Spring容器自动为这个类创建了一个bean对象,
* 将id自动设置为首字母为小写的类名
* 供使用getBean(String id , Class class)方法使用
**/
@Component//创建被增强类对象
public class Book {
public void addBook(String name) {
/*int i = 1/0;*///异常通知测试用例
System.out.println("添加书本" + name);
}
public void update(Book book) {
System.out.println("修改书本对象" + book);
}
}
运行结果
完全注解开发
使用完全注解开发,需要使用到配置类(configClass),配置类代替xml文件进行Spring的配置
@Configuration
标记这个类为一个配置类,相当于一个创建一个xml文件
@ComponenScan(basePackages={“com.hyp.Sping.Adpect”})
组件查找,用于指示Spring容器应该扫描那些包以查找组件,开启注解扫描的作用
和配置文件xml中 <context:component-scan base-package="com.hyp.Spring.Aspect"></context:component-scan>
作用相同
@EnableAspectJAutoProxy(proxyTargetClass = true)
开启切面自动代理
proxyTargetClass当该属性值为true时,代理对象基于类进行创建; 当该属性值为false时,代理对象基于接口进行创建
相当于xml文件中<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
的作用