Spring 通过注解实现属性注入 AOP 基础介绍
目录
前言
spring不仅可以通过xml形式实现依赖注入,也可以通过Java配置或者注解实现依赖注入
之前通过在applicationContext.xml 配置<bean>标签实现了将Java的bean对象注入到IOC容器中。现在通过使用注解的形式,将bean对象以不通过xml文件配置的方式实现注入:
在xml文件配置后,该类的上面会有图标显示已经注入到容器中。现在将该xml中的配置注释掉,使用注解实现:(addCatId就相当于bean标签中的 id)。
.......
import priv.base.practice.Cat;
@Component("addCatId")
public class AddCat {
public AddCat(Cat cat) {
this.cat = cat;
}
......
在xml文件中的namespace中选择context标签打钩后,新建context标签,配置扫描器(scan)如下图(多个包使用 “,”分隔),则显示该类通过不使用 xml文件的bean标签形式注入到 IOC 中。
Java配置在springBoot中比较常见,现在主要介绍通过注解代替xml配置实现属性注入
@Component
• @Repository
• @Service
• @Controller
另外三个都是基于 @Component 做出来的,@Repository对应的是DAO层。
一、使用注解实现声明式事务
事务要么全成功,要么全失败(acid),首先引入相关的jar包:
commons-dbcp下载 ,commons-pool下载 ,aopalliance.jar下载,
在实际练习时,出现一个问题就是namespace中没有tx选项,在网上查资料,解决办法如下:
首先简称是否已经引入了tx的jar包,已经引入,则打开Windows->Preference->Spring->BeansSupport, 之后找到 tx的选项,点击 apply即可。
通过使用spring连接数据库,
先导包,之后在xml中的namespace中增加tx选项,开始在xml中配置事务管理器:
增加对事务的支持;配置事务管理器;最后配置 jdbc:
<context:component-scan base-package="priv.base.auto"></context:component-scan>
<!-- 增加对事务的支持: -->
<tx:annotation-driven transaction-manager="txManager" />
<!-- 自己配置,事务管理器 txManager-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean><!-- 该bean 是jar包中的类,不必自己写 -->
<!-- 配置数据库 JDBC -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/person"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
....................
在应用中,直接使用注解的形式,(@Service 等注解)调用。
在相关的service层的代码方法需要调用dao层的crud代码需要完成事务功能,则在该方法上添加 transaction 注解。
二、AOP
Spring 中的 Aop 的通知类型有 5 种:
• 前置通知
• 后置通知
• 异常通知
• 返回通知
• 环绕通知
需要的依赖:aspectjweaver.jar(使用1.9.7版本后可以用,使用1.9.4项目有红色感叹号warning),
aopalliance.jar(上一章有)之后 编写代码 ,进行配置 首先编写相关代码
1.编写代码
通过切点,执行相关的代码(切面),在切点的前/后 位置执行切面的代码的方式称为 前置/后置 通知。 要把普通的类变成一个特殊的类(通知类)可以集成,实现接口或者注解。
代码如下(以前置通知示例,实现 MethodBeforeAdvice接口并引入源码(aop)关联):
@Component("beforeLogBeanId")
public class BeforeLog implements MethodBeforeAdvice{
public void before() {
System.out.println("this is a AOP method loging....");
}
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
// TODO Auto-generated method stub
System.out.println("执行该前置通知。。。。。。");
}
}
虽然两个方法名都是 before(),但是再执行AOP时调用的前置通知实际上只能是在下面通过关联源码后实现重写的方法before() ;另附后置通知,异常通知,环绕通知 等接口名:
2.xml配置
在xml文件中的namespace中增加 AOP 选项,进行xml配置,将切点 切面 连接起来
为了将切点和切面连接起来,首先要将二者加载到XML文件中来,beforeLog类我没有使用xml配置,直接使用 注解 @beforeLogBeanId 进行了配置。开启扫描器:
<context:component-scan base-package="priv.base.auto"></context:component-scan>
之后将方法所在的类(切点)与通知(advice 切面)进行关联 使用 标签 :aop:config
<!-- beforeLog 类直接在该类中通过注解的形式进行配置 -->
<bean id="addCatId" class="priv.base.auto.AddCat"></bean>
<!-- 实现切点与通知的关联 AOP -->
<aop:config>
<aop:pointcut expression= "execution(public void priv.base.auto.AddCat.addTest())" id="PointId"/>
<aop:advisor pointcut-ref="PointId" advice-ref="beforeLogBeanId" />
</aop:config>
注意 execution(....) 内的表达式 如果写错,整个配置文件都无法正常创造bean类。开始写的不对,写为了 priv.base.auto.AddCat.addTest() 会报错
八月 21, 2022 5:08:59 下午 org.springframework.context.support.ClassPathXmlApplicationContext refresh
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.config.internalTransactionAdvisor': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: Pointcut is not well-formed: expecting 'name pattern' at character position 41
execution( priv.base.auto.AddCat.addTest())
^Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.config.internalTransactionAdvisor': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: Pointcut is not well-formed: expecting 'name pattern' at character position 41
execution( priv.base.auto.AddCat.addTest())
^
更改后正常 打印效果如下:
expression="execution(…)" 表达式 查询
举例 | 含义 |
public boolean addStudent(org.lanqiao.entity.Student)) | 所有返回类型为boolean、参数类型为org.lanqiao.entity.Student的addStudent()方法。 |
public boolean org.lanqiao.service.IStudentService. addStudent(org.lanqiao.entity.Student) | org.lanqiao.service.IStudentService类(或接口)中的addStudent()方法,并且返回类型是boolean、参数类型是org.lanqiao.entity.Student |
public * addStudent(org.lanqiao.entity.Student) | “*”代表任意返回类型 |
public void *( org.lanqiao.entity.Student) | “*”代表任意方法名 |
public void addStudent(..) | “..”代表任意参数列表 |
* org.lanqiao.service.*.*(..) | org.lanqiao.service.IStudentService包中,包含的所有方法(不包含子包中的方法) |
* org.lanqiao.service..*.*(..) | org.lanqiao.service.IStudentService包中,包含的所有方法(包含子包中的方法) |
其他AOP通知类型
AOP重点关注其中的xml配置,理解内部的逻辑,代码编写中注意实现对应通知方式的接口。后置通知和前置通知几乎一样,不再赘述。异常通知需要自己写对应的方法,如下:
环绕通知比较强大,需要单独找时间自行练习了
实现AOP的通知类 除了进行实现接口外 也可以 使用注解,具体操作方式基本一样,就是将实现接口的通知类用使用注解 (@Aspect)代替,在相应的方法上也添加注解(@Before(execution))。既在自定义的方法上添加注解后,括号内写切点。
在xml中开启对AOP注解的通知即可
<!--开启注解对AOP的支持-->
<aop: aspectj - autoproxy></aop: aspectj - autoproxy>
我自己写的练习代码:
@Component("annotationAspectId")
@Aspect //该业务类实现AOP切面方法 ,但不以实现接口的方式,直接加上注解即可
public class SampleAnno {
@Before("execution(public void priv.base.auto.SampleCat.serviceTest())")//value =
public void myBeforeMethod() {
System.out.println("this is my beforeMehod with annotation.... ");
}
}
业务类如下:
public class SampleCat {
public SampleCat(){}
public void serviceTest() {
System.out.println("test Sample with annotation AOP! ");
}
}
运行该方法打印结果:
this is my beforeMehod with annotation....
test Sample with annotation AOP!