目录
byName自动注入@Autowired和@Qualifier
Spring配置文件中开启包扫面和注册aspectj的自动代理
什么是框架
具有约束性,支撑性的架构
Spring
Spring是什么
Spring官网:Spring | Home
Spring被称为J2EE的春天,是一个分层的,full-stack的,开源的,轻量级的Java开发框架;
Spring具有控制反转(Ioc)和面向切面(AOP)两大核心,Spring框架通过声明式方式灵活的进行事务的管理,提高开发效率和质量;
Spring优势
- 方便解耦,简化开发;
Spring管理所有的对象的创建和依赖关系的维护;
- 方便集成各种优秀的框架
- 降低Java EE API的使用难度
Spring对Java EE开发中非常难用的一些API(JDBC,JavaMail,远程调用等)都提供了封装;
- 方便程序测试
- AOP编程的支持
Spring提供面向切面的编程,可以方便的实现对程序进行权限拦截和运行监控等功能。
- 声明式事务管理
只需要通过配置就可以完成对事务的管理,而无须手动封装。
Spring体系结构
Spring大约提供了20多个模块,可根据自己项目需求进行导入
Spring的核心模块
核心容器由 Spring-core,Spring-beans,Spring-context,Spring-context-support和Springexpression(SpEL,Spring 表达式语言,Spring Expression Language)等模块组成
- Spring-core 模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。
- Spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。
- context 模块建立在由 core和 beans 模块的基础上建立起来的,它以一种类似于 JNDI 注册的方式访问对象。Context 模块继承自 Bean 模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过 Servelet 容器)等功能。Context 模块也支持 JavaEE 的功能,比如 EJB、JMX 和远程调用等。ApplicationContext 接口是 Context 模块的焦点。
- Spring-context-support 提供了对第三方集成到 Spring 上下文的支持,比如缓存(EhCache,Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker,JasperReports, Velocity)等。
- Spring-expression 模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是 JSP2.1规范中定义的统一表达式语言的扩展,支持 set 和 get 属性值、属性赋值、方法调用、访问数组集
他们完整的依赖关系如图所示:
数据访问、集成
JDBC=Java Data Base Connectivity,ORM=Object Relational Mapping,OXM=Object XML
Mapping,JMS=Java Message Service
- JDBC 模块提供了 JDBC 抽象层,它消除了冗长的 JDBC 编码和对数据库供应商特定错误代码的解析。
- ORM 模块提供了对流行的对象关系映射 API 的集成,包括 JPA、JDO 和 Hibernate 等。通过此模块可以让这些 ORM 框架和 Spring的其它功能整合,比如前面提及的事务管理。
- OXM 模块提供了对 OXM 实现的支持,比如 JAXB、Castor、XML Beans、JiBX、XStream 等。
- JMS 模块包含生产(produce)和消费(consume)消息的功能。从 Spring 4.1 开始,集成了
Spring-messaging 模块。 - 事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。
Web
- Web 模块提供面向 web 的基本功能和面向 web 的应用上下文,比如多部分(multipart)文件上传功能、使用 Servlet 监听器初始化 IoC 容器等。它还包括 HTTP 客户端以及 Spring 远程调用中与web 相关的部分。
- Web-MVC 模块为 web 应用提供了模型视图控制(MVC)和 REST Web服务的实现。Spring 的MVC 框架可以使领域模型代码和 web 表单完全地分离,且可以与 Spring 框架的其它所有功能进行集成。
- Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。
- Web-Portlet 模块提供了用于 Portlet 环境的 MVC 实现,并反映了 Spring-webmvc 模块的功能。
其他模块
- AOP 模块提供了面向方面(切面)的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来;
- Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。
- Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。
- Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息;
- 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试;
Spring核心之IOC控制反转
IOC-Inversion of Control,即控制反转,是一种思想;
IOC思想是指程序的开发过程中,实例的创建不再由调用者管理,而是由Spring工厂创建,Spring容器会控制组件之间的关系,而不是由程序代码直接控制;因此,控制权由程序代码转移到了Spring工厂中,控制权发生了反转,这就是Spring的IOC思想。
Spring入门案例
创建maven项目
pom.xml添加依赖和插件
创建一个实体类
创建Spring的配置文件application.xml
使用Spring容器创建对象
获取Spring容器
Spring提供了两种IOC容器,分别为BeanFactory和ApplicationContext;
- BeanFactory
是一个基础类型的IOC容器,是一个管理Bean的工厂,它主要负责初始化各种Bean,并调用他们的声明周期方法
BeanFactory接口有多个实现类,最常用的是XmlBeanFactory();
BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource(xxx/xxx/xxx/application.xml));
其中为配置文件的全路径名。
- ApplicationContext
是BeanFactory的子接口,也被称为应用上下文。它不仅提供了BeanFactory的所有功能,还添加了对i18n(国际化)、资源访问、事件传播等方面的良好支持。
两个常用的实现类
- ClassPathXmlApplicationContext()---常用
该类从类路径ClassPath中寻找指定的XML配置文件;
ApplicationContext app = new ClassPathXmlApplicationContext(application.xml);
- FileSystemXmlApplicationContext
从指定路径下读取Spring配置文件
- BeanFactory和ApplicationContext 区别
BeanFactory在容器加载时不创建对象,只有在getBean()时才创建对象
ApplicationContext在容器加载时创建对象。
通过上下文对象获取容器中的对象
package com.kkb.test;
import com.kkb.pojo.Team;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
import java.util.Date;
public class Test01{
@Test
public void test01(){
//使用Spring容器创建对象
//1、指定Spring配置文件的名称
String springConfig = "application.xml";
//2、创建Spring对象
ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);//已经创建对象
//3、容器中的其他api
int count = context.getBeanDefinitionCount();//获取容器中对象的数量
String[] beanDefinitionNames = context.getBeanDefinitionNames();
}
}
创建非自定义对象
application.xml中补充
<bean id="date1" class="java.util.Date">
调用
Date date = (Date)context.getBean("date1");
bean标签属性
属性 | 说明 |
id | id是bean对象的唯一标识,不能添加特别字符 |
class | 指定bean对应的全路径 |
scope | 执行bean对象的创建模式和生命周期,scope="singleton"/"prototype" |
name | name是bean对象的一个标识 |
lazy-init | 是否延时加载,默认值:false。true标识延迟加载对象,当对象被调用的时候才会创建对象;false不论是否被使用,都会立即被创建 |
init-method | 创建对象之后执行的初始化方法 |
destory-method | 对象销毁方法 |
示例演示
Team 类中增加方法
public void init(){
System.out.println("Team-------init()");
}
public void destory(){
System.out.println("Team--------destory()");
}
application.xml增加如下内容
<!--//singleton:单例,默认值,容器启动完毕之后,单例对象就被创建了,且只有唯一的一个对象
//prototype:使用时,对象才被创建,每次获取时都会创建一个对象
init-method:对象创建后立即调用的方法,名字自定义
destroy-method:在spring容器关闭时调用的方法
-->
<bean id="team2" class="com.kkb.pojo.Team" scope="singleton" lazy-init="true" init-method="init" destroy-method="destroy"/>
<bean id="team3" class="com.kkb.pojo.Team" scope="prototype"/>
Spring容器创建对象的方式
使用默认的构造方法
使用带参数的构造方法
使用工厂类
三种方式案例
Team类中添加带参数的构造方法
public Team(Integer id,String name,String location){
this.id = id;
this.name = name;
this.location = location;
System.out.println("Team-------带参数的构造方法");
}
创建工厂类
public class MyFactory{
//实例方法
public Team instanceFun(){
System.out.println("MyFactory--------instanceFun()")
return new Team(1003,"湖人","洛杉矶");
}
//静态方法
public static Team staticFun(){
System.out.println("MyFactory---------staticFun()");
return new Team(1004,"小牛","达拉斯");
}
}
创建新的配置文件creatType.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<!--1、默认构造函数 -->
<bean id="team1" class="com.kkb.pojo.Team"/>
<!--2、通过带参数的构造方法 -->
<bean id="team2" class="com.kkb.pojo.Team">
<!-- name表示参数的名称-->
<constructor-arg name="id" value="1001"/>
<constructor-arg name="name" value="勇士"/>
<constructor-arg name="location" value="金州"/>
</bean>
<bean id="team3" class="com.kkb.pojo.Team">
<!--index:表示参数的下标索引-->
<constructor-arg index="0" value="1002"/>
<constructor-arg index="1" value="热火"/>
<constructor-arg index="2" value="迈阿密"/>
</bean>
<!--3、通过工厂方法 -->
<!--3.1、静态方法 等价于 Team team1 = MyFactory.staticFun() -->
<bean id="staticTeam" class="com.kkb.pojo.MyFactory" factory-method="staticFun"/>
<!--3.2、实例方法 等价于
MyFactory f = new MyFactory();
Team team = f.instanceFun();
-->
<bean id="fa" class="com.kbb.pojo.MyFactory"/>
<bean id="instanceTeam" factory-bean="fa" factory-method="instanceFun"
</beans>
基于xml的DI
DI--Dependence Injection,即依赖注入:是组件之间依赖关系由容器在运行期间决定,即由容器动态的将 某个依赖关系注入到组件之中。
IOC是一种思想,其实现方式多种多样,DI就是其中一种。
Ioc和DI是同一个概念的不同角度描述。IoC是一种思想,概念,DI是实现它的手段。Spring框架使用依赖注入实现IoC.
Spring 容器是一个超级大工厂,负责创建、管理所有的 Java 对象,这些 Java 对象被称为 Bean。
Spring 容器管理着容器中 Bean 之间的依赖关系,Spring 使用“依赖注入”的方式来管理 Bean 之间的依赖关系。使用 IoC 实现对象之间的解耦和。
注入方式分类
bean实例在调用无参构造器创建对象后,就要对bean对象的属性进行初始化,初始化是由容器自动完成的,称为注入。
通过set方法(常用)
set 注入也叫设值注入是指,通过 setter 方法传入被调用者的实例。这种注入方式简单、直观,因而在Spring 的依赖注入中大量使用。
通过构造方法注入
构造注入是指,在构造调用者实例的同时,完成被调用者的实例化。使用构造器设置依赖关系。
自动注入
对于引用类型的注入,也可不在配置文件中显示的注入,可以通过标签设置autowire属性值,为引用类型属性进行隐士自动注入(默认是不自动注入引用类型属性)。根据自动注入判断标准不同,可以分为两种:
byName:根据名称注入;
byType:根据类型自动注入;
- byName
当配置文件中被调用者bean的id值与代码中调用者bean类的属性名相同时,可以使用byName方式;
- byType
要求,配置文件中被调用者bean的class属性指定的类,要与代码中调用者bean类的某引用类型属性类型同源,即要么相同,要么有父子关系。注意,这时这样的同源的被调用的bean类型只能有一个
示例
创建TeamDao.java
package com.xiaohan.dao;
public class TeamDao {
public void add(){
System.out.println("TeamDao----------add-----");
}
}
创建TeamService.java
package com.xiaohan.service;
import com.xiaohan.dao.TeamDao;
public class TeamService {
private TeamDao teamDao;
public void add(){
teamDao.add();
System.out.println("TeamService------------add-----------");
}
public TeamService(){}
public TeamService(TeamDao teamDao){
this.teamDao = teamDao;
}
public TeamDao getTeamDao() {
return teamDao;
}
public void setTeamDao(TeamDao teamDao) {
this.teamDao = teamDao;
}
}
创建配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<bean id="teamDao" class="com.xiaohan.dao.TeamDao"></bean>
<bean id="teamService" class="com.xiaohan.service.TeamService">
<!--使用set方式注入属性值-->
<property name="teamDao" ref="teamDao"/>
</bean>
<bean id="teamService2" class="com.xiaohan.service.TeamService">
<!--使用构造方法注入属性值-->
<constructor-arg name="teamDao" ref="teamDao"/>
</bean>
<bean id="teamService3" class="com.xiaohan.service.TeamService" autowire="byName">
<!--按名称自动注入:查找容器中id名与属性名一致的对象自动注入-->
</bean>
<bean id="teamService4" class="com.xiaohan.service.TeamService" autowire="byType">
<!-- 按类型自动注入,查找容器中类型与属性类型相同或者符合is-a关系的对象进行注入,-->
</bean>
</beans>
创建测试
import com.xiaohan.service.TeamService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDemo {
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("DI.xml");
TeamService teamService = (TeamService) context.getBean("teamService");
teamService.add();
TeamService teamService2 = (TeamService) context.getBean("teamService2");
teamService2.add();
TeamService teamService3 = (TeamService) context.getBean("teamService3");
teamService3.add();
TeamService teamService4 = (TeamService) context.getBean("teamService4");
teamService4.add();
}
}
基于注解实现IOC--重要
声明bean的注解--@Component
在类上添加注解@Component表示该类创建对象的权限交给Spring容器。注解的value属性 用于指定bean的id 值,value可以省略 默认类名首字母小写。
除此之外,Spring还提供了其他3个用于创建对象的 注解,
@Repository:用于dao实现类的注解;
@Service:用于service实现类的注解;
@Controller:用于controller实现类的注解。
区别:@Service创建业务层对象,业务层对象可以加入事务功能,@Controller注解创建的对象可以作为处理器接收用户的请求;
@Repository,@Service,@Controller 是对@Component 注解的细化,标注不同层的对象。即持久层对象,业务层对象,控制层对象。
包扫描
在Spring配置文件中配置组件扫描器,用于在指定的包中扫描注解,如果没有被扫描,添加的创建对象的注解不生效。
<!--多个包扫描-->
<!--方式1:使用多个标签-->
<context:component-scan base-package="com.xiaohan.dao"/>
<context:component-scan base-package="com.xiaohan.service"/>
<!--方式2:使用(,)或(;)隔开-->
<context:component-scan base-package="com.xiaohan.dao,com.xiaohan.service"/>
<!--方式3:指定到父包-->
<context:component-scan base-package="com.xiaohan"/>
属性注入@Value
需要在属性上使用注解@Value,该注解的value属性用于指定要注入的值,注意无论是什么类型的值,都需要用双引号引起来。
byType自动注入@Autowired
需要在引用属性上使用注解@Autowired,该注解默认使用按类型 自动装配Bean的方式。
byName自动注入@Autowired和@Qualifier
需要在引用属性上联合使用注解@Autowired与@Qualifier。@Qualifier的value属性用于指定要匹配的Bean的id值。
@Autowired还有一个属性required,默认值为true,表示当匹配失败后,会终止程序运行;false,表示若匹配失败,将被忽略,未匹配的属性值为null;
自动注入@Resource
Spring提供了对jdk中@Resource注解的支持。@Resource注解既可以按照名称匹配Bean,也可以按类型匹配Bean。默认是按名称注入,若按名称不能注入,则会按照类型进行注入。要求jdk6以上版本,@Resource可在属性上,也可以在set方法上。可用name属性指定需要匹配的bean的id值;
Spring核心AOP
AOP--Aspect Oriented Programming的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP的作用,不修改源码的情况下,程序运行期间对方法进行功能增强。
好处:
- 减少代码的重复,提高开发效率,便于维护。
- 专注于核心业务的开发
关于AOP的底层实现原理动态代理请参考文章,动态代理
Spring AOP相关概念和术语
Spring的AOP实现底层就是对动态代理的代码进行了封装。封装后,我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。
- Target(目标对象)
要被增强的对象,一般是业务逻辑类的对象。
- Proxy(代理)
一个类被AOP织入增强后,就产生一个结果代理类。
- Aspect(切面)
表示增强的功能,就是一些代码完成的某个功能,非业务功能。是切入点和通知的结合。
- Joinpoint(连接点)
所谓连接点就是那些被拦截到的点,在Spring中,这些点指的是方法(一般是类中的业务方法),因为Spring只支持方法类型的连接点。
- Pointcut(切入点)
切入点指声明的一个或多个连接点的集合,通过切入点指定一组方法。
被标记为final的方法是不能作为连接点与切入点的,因为最终的是不能被修改的,不能被增强的。
- Advice(通知/增强)
所谓通知就是拦截到Joinpoint后,所要做的事情就是通知。通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行。通知类型不同,切入时间不同。
通知类型,前置通知,后置通知,异常通知,最终通知,环绕通知
切入点定义切入的位置,通知定义切入的时间
- Weaving(织入)
是指把增强应用到目标对象来创建新的代理对象的过程。
Aspect J的切入点表达式
以上表达式共四个部分
execution(访问权限 方法返回值 方法声明(参数)异常类型);
切入点表达式要匹配的对象就是目标方法的方法名。所以,execution表达式就是方法的签名。
提示:表达式中黑色文字标识可省略部分,各部分间用空格分开。在其中可以使用以下符号
符号 | 含义 |
* | 0-多个任意字符 |
.. | 用在方法参数中,表示任意个参数;用在包名后,表示当前及其子包路径 |
+ | 用在类名后,表示当前及其子类;用在接口后,表示当前接口及其实现类 |
示例:
execution(* com.xiaohan.service.*.*(..))
指定切入点:定义在service包里的任意类的任意方法。
execution(* com.xiaohan.service..*.*(..))
定义在service包及其子包中的任意类的任意方法。
execution(* com.xiaohan.service.IUserService+.*(..))
IUserService 若为接口,则为接口中的任意方法及其所有实现类中的任意方法;若为类,
则为该类及其子类中的任意方法。
注解方式实现AOP
代理方式的选择,是否实现了接口,有接口就选择JDK代理,没有就选择CGLIB动态代理;
引入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
在Spring配置文件中引入约束
<?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
">
</beans>
创建核心业务类
public interface IService {
void add(int id,String name);
boolean update(int num);
}
public class UserService implements IService{
@Override
public void add(int id, String name) {
System.out.println("UserService----------------add()-----");
}
@Override
public boolean update(int num) {
System.out.println("UserService-----------update()--------");
if(num>666){
return true;
}
return false;
}
}
public class NbaService implements IService{
@Override
public void add(int id, String name) {
System.out.println("NBAService-------add()");
}
@Override
public boolean update(int num) {
System.out.println("NBAService-----------update()");
if(num>666){
return true;
}
return false;
}
}
定义切面类
package com.xiaohan.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
@Component//切面对象的创建权限依然交给spring容器
@Aspect//框架注解,标识当前类是一个切面类
public class MyAspect {
/**
* 当较多的通知增强方法使用相同的 execution 切入点表达式时,编写、维护均较为麻烦。
* AspectJ 提供了@Pointcut 注解,用于定义 execution 切入点表达式。
* 其用法是,将@Pointcut 注解在一个方法之上,以后所有的 execution 的 value 属性值均
* 可使用该方法名作为切入点。代表的就是@Pointcut 定义的切入点。
* 这个使用@Pointcut 注解方法一般使用 private 的标识方法,即没有实际作用的方法。
*/
@Pointcut("execution(* com.xiaohan.service..*.*(..))")
private void pointCut1(){}
@Pointcut("execution(* com.xiaohan.service..*.add*(..))")
private void pointCut2(){}
/*
* 声明前置通知
* */
@Before("pointCut1()")
public void before(JoinPoint jp){
System.out.println("前置通知:在目标方法执行之前被调用的通知");
String name = jp.getSignature().getName();
System.out.println("拦截的方法名称:"+name);
Object[] args = jp.getArgs();
System.out.println("方法的参数格式:"+args.length);
System.out.println("方法的参数列表:");
for (Object arg:args){
System.out.println("\t"+arg);
}
}
/*
* AfterReturning注解声明的后置通知
* value:表式切入点表达式
* returning属性表示,返回的结果,如果需要的话可以在后置通知的方法中修改结果
* */
@AfterReturning(value = "pointCut2()",returning = "result")
public Object afterReturn(Object result){
if(result!=null){
boolean res = (boolean) result;
if(res){
result=false;
}
}
System.out.println("后置通知:在目标方法执行之后被调用的通知,result="+result);
return result;
}
/*
* Around注解声明环绕通知
* ProceedingJoinPoint中的proceed方法表示目标方法被执行
* */
@Around(value = "pointCut1()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕方法-------目标方法执行之前");
Object proceed = pjp.proceed();
System.out.println("环绕方法,目标方法执行之后");
return proceed;
}
/*
* AfterThrowing注解声明异常通知方法
* value:表示切入点表达式
* returning:返回的结果,
* */
@AfterReturning(value = "pointCut1()",throwing="ex")
public void exception(JoinPoint jp,Throwable ex){
System.out.println("异常通知,在目标方法出现异常时才会被调用的通知,否则不执行");
System.out.println(jp.getSignature()+"方法出现异常,异常信息是:"+ex.getMessage());
}
/*
* @After:最终通知
* */
@After("pointCut1()")
public void myFinally(){
System.out.println("最终通知,无论是否出现异常都是最后被调用的通知");
}
}
业务类和切面类添加注解
在定义好切面Aspect后,需要通知Spring容器,让容器生成“目标类+切面”的代理对象。这个代理是由容器自动生成的。只需要在Spring配置文件中注册一个基于aspectJ的自动代理生成器,其就会自动扫描到@Aspect注解,并按通知类型与切入点,将其织入,并生成代理。
Spring配置文件中开启包扫面和注册aspectj的自动代理
测试类
@Test
public void test02(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
userService.add(1001,"湖人");
System.out.println("---------------------------");
boolean update = userService.update(888);
System.out.println("update 结果="+update);
System.out.println("----------------------------");
NbaService nbaService = (NbaService) context.getBean("nbaService");
nbaService.add(1002,"热火");
System.out.println("-----------------------------");
boolean update2 = nbaService.update(888);
System.out.println("update2 结果="+update2);
}