- 一、Spring介绍
- 二、IoC
- 原理
- 实例
- 例二(Spring注入类属性)略
- 三、IoC创建对象的方式,原理
- 1.默认使用无参构造
- 2.有参构造——下标赋值
- 3.有参构造——类型赋值(不推荐)
- 4.有参构造——直接通过参数名来设置
- 总结
- 四、Spring配置
- 别名
- Bean的配置
- import
- 五、DI依赖注入
- Set方式注入【重点】
- 其它方式/拓展方式注入
- 六、bean的作用域
- 七、bean的自动装配
- ByName,ByType自动装配
- 使用注解自动装配--@Autowired
- 注解拓展
- 八、使用注解开发
- 注解说明
- 实例
- 纯Java的配置方式
- 九、代理模式proxy
- 静态代理
- 动态代理
- 例一 —— 中介帮房东租房子
- 例二 —— 增删改查添加日志功能
- 例三 —— InvocationHandler自动生成代理修改例一
- 例四 —— InvocationHandler类(通用类)修改例二
- 十、AOP
- Aop在Spring中的作用
- 实现方法
- 不变的类
- 方式一:使用原生Spring API接口
- 方式二:自定义来实现AOP【主要是切面定义】
- 方式三:使用注解实现!
Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架
Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版本
Rod Johnson :Spring framework创始人
spring理念:使现有的技术更加容易使用,本身是一个大杂烩
Spring 融合件
优点:
Spring是一个开源的免费的框架(容器)!
Spring是一个轻量级,非入侵式的框架
控制反转(IoC) 面向切面(AOP)
支持事务的处理,对框架整合的支持!
缺点:
发展了太长时间,违背了原来的理念你!配置十分繁琐。人称:配置地狱
总结:Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架
拓展
Spring Boot
一个快速开发的脚手架
基于Spring Boot可以快速的开发单个微服务
约定大于配置
Spring Cloud
基于Spring Boot实现的
学习Spring Boot的前提,需要完全掌握Spring及SpringMVC!承上启下的作用
二、IoC 原理控制反转:
public class UserServiceImpl implements UserService {
private UserDao userDao;
//使用set进行动态实现值的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser() {
userDao.getUser();
}
}
之前,程序是主动创建对象!控制权在程序员手上!
使用set注入后,程序不在具有主动性,而是变成了被动的接受对象!
这种思想,从本质上解决了问题,我们程序员不用去管理对象的创建了。系统的耦合性大大降低,可以更加专注的在业务的实现上!这时IOC的原型!
ps:个人总结,通过set方法注入,只需在调用ServiceImpl方法时new一个dao层的方法即可代替之前重复创建Service和ServiceImpl的大量重建
额外:
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从loc容器中取出需要的对象
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法
控制反转是一种通过从描述(XML或注解)并通过第三方去生产或获取特定对象的方法。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)
所谓IoC,对象由Spring来创建,管理,装配!
实例DAO:
public interface UserDao {
void getUser();
}
public class UserDaoImpl implements UserDao{
public void getUser() {
System.out.println("UserDao执行");
}
}
public class UserDaoMysqlImpl implements UserDao{
public void getUser() {
System.out.println("Mysql处理");
}
}
Service:
public interface UserService {
void getUser();
}
public class UserServiceImpl implements UserService {
private UserDao userDao;
//使用set进行动态实现值的注入
//可见即使有两个DaoImpl,ServiceImpl通过set注入,一个即可
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser() {
userDao.getUser();
}
}
在resource中配置beans.xml
这里ref为mysqlImpl,绑定的就是UserDaoMysqlImpl
测试代码:
@Test
public void getUser() {
//获取ApplicationContext; 拿到Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//有了容器,需要什么可以直接get
UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("UserServiceImpl");
userServiceImpl.getUser();
}
这里执行后输出就为“Mysql处理”
这里ref改为impl,测试代码不变
输出为“UserDao执行”
类:
public class Hello {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + ''' +
'}';
}
}
beans.xml
这里的value就是hello的str属性
测试代码:
public class HelloTest {
@Test
public void MyTest() {
//获取Spring的上下文对象
ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
//我们的对象都在Spring中的管理了,我们要使用直接去里面取出来就可以了
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello);
}
}
输出:hello
输出的就是beans.xml的值
先来两个实体类:
public class User {
private String name;
public User() {
System.out.println("User的无参构造!");
}
public User(String name) {
this.name=name;
System.out.println(name+"的有参构造!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "name=" + name ;
}
}
public class UserT {
private String name;
public UserT() {
System.out.println("UserT的无参构造!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "name=" + name ;
}
}
beans.xml不变的部分
1.默认使用无参构造
beans.xml创建对象
测试代码:
public void test2() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user=(User) context.getBean("user");
System.out.println(user);
}
@Test
public void testT() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserT usert=(UserT) context.getBean("userT");
System.out.println(usert);
}
2.有参构造——下标赋值
beans.xml配置
测试代码:
@Test
public void test2() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user=(User) context.getBean("user");
System.out.println(user);
}
3.有参构造——类型赋值(不推荐)
只改bean就行,测试代码不变
4.有参构造——直接通过参数名来设置
总结
IoC创建对象的方式:
1.使用无参构造创建对象,默认!
beans.xml配置:
实例化:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user=(User) context.getBean("user");
2.假设我们要使用有参构造创建对象
第一种方式:下标赋值
实体类:
public User(String name) {
this.name=name;
System.out.println(name+"的有参构造!");
}
beans.xml配置
实例化同上
第二种方式:类型赋值(不推荐使用)
beans.xml配置
第三种方式:直接通过参数名来设置
beans.xml配置
总结:在配置文件加载的时候,容器中管理的对象就已经初始化了!
从spring容器中取出的对象都是同一个
四、Spring配置
实体类:
public class UserT {
private String name;
public UserT() {
System.out.println("UserT的无参构造!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "name=" + name ;
}
}
别名
beans.xml配置
测试代码
@Test
public void testT() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserT usert=(UserT) context.getBean("abc");
System.out.println(usert);
}
Bean的配置
beans.xml
测试代码
@Test
public void testT() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserT usert=(UserT) context.getBean("u4");
System.out.println(usert);
}
import
这个import,一般用于团队开发使用,他可以将多个配置文件,导入合并为一个
在beans.xml同级目录下创建beans2.xml,beans3.xml,
然后创建applicationContext.xml
测试代码也可以正常运行
@Test
public void testT2() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserT usert=(UserT) context.getBean("u4");
System.out.println(usert);
}
五、DI依赖注入
构造器注入方法上面已经说过了,这里看看其他注入
Set方式注入【重点】- 依赖注入:Set注入!
-- 依赖:bean对象的创建依赖于容器
-- 注入:bean对象中的所有属性,由容器来注入!
看看复杂类型的对象注入
public class Student {
private String name;
private Address address;
private String[] books;
private List hobbies;
private Map card;
private Set games;
private String wife;
private Properties info;
}
//set,get,toString方法略
public class Address {
private String address;
}
//set,get,toString方法略
beans.xml
《山海经》 《道德经》 《周易》
听歌 敲代码 睡觉 群星 dark soul 死神 无名之人 无 粪球 破烂的衣物
测试还是一样
其它方式/拓展方式注入p命名空间约束和c命名空间约束
实体类:
public class User {
private String name;
private int age;
}//set,get,toString方法略
beans.xml
测试代码和上面一样
ps:必须要有有参构造器
1.单例模式(Spring默认)——singletonps:个人小结,singleton模式下在同一次会话ApplicationContext中通过 context.getBean("user2");创建出来的对象都是一个 2.原型模式——prototype ps:prototype模式下创建出来的对象都是单独的(新的) 3.其余的request,session,application,这些只能在web开发中使用到
beans.xml
测试代码:
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Object user = context.getBean("user2");
Object user2 = context.getBean("user2");
System.out.println(user);
System.out.println(user==user2);
}
输出:
User{name=‘尼德霍格’, age=18}
false
如果去掉beans.xml的scope=“prototype”,则默认为单例模式,输出就是:
User{name=‘尼德霍格’, age=18}
true
- 自动装配是Spring满足bean依赖的一种方式!
- Spring会在上下文中中自动寻找,并自动给bean装配属性!
- Spring中有三种装配的方式
1.在xml中显示的配置
2.在java中显示配置
3.隐式的自动装配bean【重点】
ByName,ByType自动装配
三个实体类:
public class Cat {
public String bark() {
return "你是猫";
}
@Override
public String toString() {
return "Cat:" + bark();
}
}
public class Dog {
public String bark(){
return "你是狗";
}
@Override
public String toString() {
return "Dog:"+bark();
}
}
public class Person {
private Cat cat;
private Dog dog;
private String name;
@Override
public String toString() {
return "Person{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + ''' +
'}';
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
beans.xml
测试代码
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = context.getBean("person", Person.class);
System.out.println(person);
}
使用注解自动装配–@Autowired
-- 导入约束:context约束
-- 配置注解的支持:
**@Autowired **
-- @Autowired 注解实体类,可以直接在属性上使用即可!也可以在set方式上使用!
使用@Autowired 我们可以不用编写Set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在,且符合名字byname!
可见用了@Autowired 后连set方法都可以不用了
实例:
其他不变
Person类:
public class Person {
@Autowired
private Cat cat;
//如果显示定义了 @Autowired的required = false,说明这个对象可以为null,否则不允许为空
//用了@Autowired 后连set方法都可以不用了
@Autowired(required = false)
private Dog dog;
private String name;
@Override
public String toString() {
return "Person{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + ''' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
beans.xml
测试输出:
Person{cat=Cat:你是猫, dog=Dog:你是狗, name=‘山沟沟’}
-
@Nullable 字段标记了这个注解,说明这个字段可以为null;
-
@Qualifier(value = “?”)
@Autowired @Qualifier(value = "dog22") private Dog dog; private String name;
-
@Resource注解:java自带的注解
ps:个人理解
@Resource注解无参时,当bean.xml中配置了单个Cat类时,采用的时byType自动装配,多个时采用的时byName自动装配,默认匹配id为cat的bean,否则报错 @Resource注解有参时, @Resource(name = "cat1") ,匹配id为name的值的bean @Resource private Cat cat;
注解执行装配顺序等说明
-
@Autowired顺序: byType–》byName–》@Qualifier
-
@Qualifier没用之前@Autowired标签默认按byType自动装配,@Qualifier用之后按byName自动装配
-
@Qualifier标签给Dog附上ID:
@Autowired(required = false) @Qualifier(value = "dog22") private Dog dog;
-
bean Dog配置id和 @Qualifier标签ID一致:
- 在Spring4之后,要使用注解开发,必须要保证aop的包导入了
- 使用注解需要导入context约束,增加注解的支持
- @Autowired : 自动装配通过类型,名字
如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value=“xxx”) - @Nullable 字段标记了这个注解,说明这个字段可以为null
- @Resource : 自动装配通过名字,类型
- @Component : 组件,放在类上,说明这个类被Spring管理了,就是bean!
实体类:
//等价于//Component:组件 @Component @Scope("singleton") public class User { //相当于 @Value("Jerry") public String name; }
beans.xml
测试代码:
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user", User.class);
System.out.println(user.name);
}
纯Java的配置方式
在SpringBoot中随处可见!
实体类:
//这个注解表示这个类被Spring接管了(ps:只有说明/标记的用处,无实际意义)
@Component
public class User {
private String name;
@Override
public String toString() {
return "User{" +
"name='" + name + ''' +
'}';
}
public String getName() {
return name;
}
//属性注入值
@Value("羲和")
public void setName(String name) {
this.name = name;
}
}
PersonConfig类:
//类似@Component,也会被Spring容器托管,代表一个配置了,相当于beans.xml
@Configuration
@ComponentScan("com.person.pojo")
@import(PersonConfig2.class)//导入其它配置
public class PersonConfig {
//注册一个bean,相当于一个bean标签,这个方法的名字就相当于bean标签中的id属性,这个方法的返回值就相当于bean标签中的class属性
@Bean
public User getUser(){
return new User();//就是返回要注入到bean的对象!
}
}
测试代码:
@Test
public void test() {
//如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig 上下文来获取容器,通过配置类的class对象加载
ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig.class);
User user = context.getBean("getUser", User.class);
System.out.println(user);
}
//输出User{name='羲和'}
九、代理模式proxy
静态代理
抽象角色:一般会使用接口或者抽象类来解决 真实角色:被代理的角色 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作 客户:访问代理对象的人!
步骤:
1.接口
2.真实角色
3.代理角色
4.客户访问代理角色
静态代理好处:
- 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
- 公共业务就交给了代理角色!实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理!
缺点: - 一个真实角色就会产生一个代理角色;代码量会翻倍–开发效率会变低
- 动态代理和静态代理角色一样
- 动态代理的代理类是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口—JDK动态代理【暂时使用】
- 基于类:cglib
- java字节码实现:javasisit
需要了解两个类:Proxy(代理),InvocationHandler(调用处理程序)
动态代理好处:
- 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
- 公共业务就交给了代理角色!实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理!
- 一个动态代理类代理的是一个接口,一般就是对应的一个业务
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可!
//租房
public interface Rent {
public void rent();
}
//房东要出租房子
public class Host {
public void rent(){
System.out.println("房东要出租房子!");
}
}
代理类Proxy:
//代理
public class Proxy implements Rent {
private Host host;
public Proxy(){
}
public Proxy(Host host) {
this.host = host;
}
public void rent() {
seeHouse();
host.rent();
contract();
fee();
}
public void seeHouse(){
System.out.println("看房");
}
public void fee(){
System.out.println("收中介费");
}
public void contract(){
System.out.println("签合同");
}
}
测试类:
public class Client {
public static void main(String[] args) {
Host host=new Host();
//代理,中介帮房东租房子,中介会有一些附属操作
Proxy proxy = new Proxy(host);
proxy.rent();
}
}
例二 —— 增删改查添加日志功能
public interface UserService {
void add();
void delete();
void update();
void query();
}
//真实对象
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("修改了一个用户");
}
public void query() {
System.out.println("查询了一个用户");
}
}
代理UserServiceProxy类:
public class UserServiceProxy implements UserService{
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void add() {
log("add");
userService.add();
}
public void delete() {
log("delete");
userService.delete();
}
public void update() {
log("update");
userService.update();
}
public void query() {
log("query");
userService.query();
}
//日志方法
public void log(String msg){
System.out.println("使用了"+msg+"方法");
}
}
测试类:
public class Client {
public static void main(String[] args) {
UserService userService=new UserServiceImpl();
UserServiceProxy proxy=new UserServiceProxy();
proxy.setUserService(userService);
proxy.add();
}
}
例三 —— InvocationHandler自动生成代理修改例一
//租房
public interface Rent {
public void rent();
}
//房东要出租房子
public class Host implements Rent{
public void rent(){
System.out.println("房东要出租房子!");
}
}
代理类ProxyInvocationHandler:
//用这个类,自动生成代理
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成得到的代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
//处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
//动态代理的本质,就是使用反射机制
Object result = method.invoke(rent, args);
fee();
return result;
}
public void seeHouse(){
System.out.println("看房子");
}
public void fee(){
System.out.println("收中介费");
}
}
测试类:
public class Client {
public static void main(String[] args) {
//真实角色
Host host=new Host();
//代理角色
ProxyInvocationHandler pih=new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们要调用的接口对象
pih.setRent(host);
Rent proxy = (Rent) pih.getProxy(); //这里的proxy就是动态生成的,我们并没有写
proxy.rent();
}
}
例四 —— InvocationHandler类(通用类)修改例二
public interface UserService {
void add();
void delete();
void update();
void query();
}
//真实对象
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("修改了一个用户");
}
public void query() {
System.out.println("查询了一个用户");
}
}
代理类ProxyInvocationHandler:
//用这个类,自动生成代理
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到的代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
//处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
//动态代理的本质,就是使用反射机制
Object result = method.invoke(target, args);
return result;
}
public void log(String msg){
System.out.println("[log]执行了"+msg+"方法");
}
}
测试类:
public class Client {
public static void main(String[] args) {
//真实角色
UserService userService=new UserServiceImpl();
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService);//设置要代理的对象
//动态生成代理类
UserService proxy = (UserService) pih.getProxy();
proxy.add();
proxy.query();
proxy.update();
proxy.delete();
}
}
```java
public class Client {
public static void main(String[] args) {
//真实角色
UserService userService=new UserServiceImpl();
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService);//设置要代理的对象
//动态生成代理类
UserService proxy = (UserService) pih.getProxy();
proxy.add();
proxy.query();
proxy.update();
proxy.delete();
}
}
十、AOP
- AOP:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术
提供声明式事务;允许用户自定义切面
- 横切面关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切面关注点。如日志,安全,缓存,事务等等…
- 切面(ASPECT):横切关注点,被模块化的特殊对象。即,它是一个类
- 通知(Advice):切面必须要完成的工作。即它是类中的一个方法。
- 目标(Target):被通知目标
- 代理(Proxy):向目标对象应用通知之后创建的对象
- 切入点(PointCut):切面通知执行的"地点"的定义
- 连接点(JointPoint):与切入点匹配的执行点
方式一:使用Spring的API接口【主要是SpringAPI接口实现】
方式二;自定义来实现AOP【主要是切面定义】
方式三:使用注解实现!
public interface UserService {
void add();
void delete();
void update();
void select();
}
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("修改了一个用户");
}
public void select() {
System.out.println("查询了一个用户");
}
}
测试代码:
@Test
public void add() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理的核心是接口
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
方式一:使用原生Spring API接口
需要横切入的类
public class Log implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+target.getClass().getName()+"的"+method.getName()+"方法");
}
}
//和
public class AfterLog implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"方法 返回结果为:"+returnValue);
}
}
applicationContext.xml配置
输出:
执行了com.person.service.UserServiceImpl的add方法 增加了一个用户 执行了add方法 返回结果为:null
- 输出顺序和AfterLog,Log继承的类有关
- public class AfterLog implements AfterReturningAdvice{}
- public class Log implements MethodBeforeAdvice{}
需要切入的类:
public class DiyPointCut {
public void before1(){
System.out.println("=======方法执行前==========");
}
public void after1(){
System.out.println("=======方法执行后==========");
}
}
applicationContext.xml:
测试输出:
=======方法执行前========== 增加了一个用户 =======方法执行后==========方式三:使用注解实现!
切面:
@Aspect//标注这个类是一个切面
public class AnnotationPointCut {
@Before("execution(* com.person.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("======方法执行前=========");
}
@After("execution(* com.person.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("-------方法执行后----------");
}
//在环绕增强中,我们可用给定一个参数,代表我们要获取要处理切入的点
@Around("execution(* com.person.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Signature signature= jp.getSignature();//获得签名 可忽略
System.out.println("signature:"+signature);
//执行方法
Object proceed = jp.proceed();
System.out.println("环绕后");
System.out.println(proceed);//可忽略
}
}
applicationContext.xml:
测试输出:
环绕前 signature:void com.person.service.UserService.add() ======方法执行前========= 增加了一个用户 -------方法执行后---------- 环绕后 null



