Spring详细学习
Spring框架概念&目的&特点
概念:轻量级开源的JAVAEE框架
目的:简化企业开发而存在的框架
特点:
(1)方便解耦,简化开发
(2)AOP编程支持
(3)方便程序测试
(4)方便和其他框架整合入mybatis
(5)方便对事物的操作
(6)降低API的开发难度
IOC容器
IOC(控制翻转)
概念:把创建过程交给spring进行管理
IOC概念及底层原理:
: 什么是IOC?
把对象的创建和对象之间引用的过程都交给Spring进行管理,目的是耦合性降低
: IOC的底层原理:
xml解析、工厂设计模式、反射
IOC接口(Beanfactory)
IOC的思想基于IOC容器完成,IOC底层就是对象的工厂
Spring提供IOC容器实现方式:(两个接口)
1、BeanFactory
是IOC中最基本的实现方式,是spring内部使用的接口,不提供开发人员使用
特点:加载配置文件是不会创建对象,在获取或使用对象时才会创建对象
2、ApplicationContext
是BeanFactory的子接口,功能强大,面向开发人员
特点:在加载配置文件时,就会把配置文件对象进行创建
平常使用这种方式是把创建对象这个过程交给服务器完成,就不会在操作时完成。
3、ApplicationContext接口的实现类
CtrlH打开类结构
FileSystemXmlApplicationContext是盘的路径
ClassPathXmlApplicationContext是类路径
IOC操作 Bean管理(创建对象&注入属性)
: 什么是Bean管理,两个操作:
1、由spring创建对象
2、spring注入属性
IOC操作Bean管理(基于xml配置文件)
1)基础XML方式创建对象
1.在xml文件中使用bean标签,标签里加上对应的属性,就可以实现对象的创建
2.bean下很多属性,常见属性如下:
id属性:唯一标识
class属性:类全路径(包类路径)
name属性:和id属性一样,还可加特殊符号,id中不可,都用id属性
3.默认情况是执行无参数的构造方法,完成对象的创建
2)基础XML方式注入属性
DI:依赖注入,就是注入属性,DI是IOC中一种具体实现
第一种方式使用setter方法进行注入
第一步:创建属性、创建set方法
第二步:在Spring配置文件配置对象创建,配置属性注入
Set方法简化写法:(了解)
P名称空间注入,简化XML配置方式
第一步:XML中增加P约束:
第二步:在bean标签中进行操作
第二种注入方式通过有参数的构造注入
第一步:创建类定义属性,然后创建带属性的构造方法
第二步:在spring配置文件中进行配置
其中constructor-arg中有index属性是按参数的索引比如index=0,取第一个,用确定值比较好。
IOC操作Bean管理(基于xml配置文件,注入其他类型属性)
字面量
1)null值:在property中加入null标签
设置null值
<property name="address">
<null/>
</property>
2)特殊符号
<!--属性值中包含特殊符号
1.<>进行转译< >
2.把带特殊符号的内容写到CDATA
-->
<property name="address">
<value><![CDATA[<<测试>>]]>
</value>
</property>
注入属性-外部bean
(1)创建2个类service类和dao类
(2)在service调用dao里面的方法
(3)在spring配置文件中配置
//创建UserDao属性,生成对应的setter方法
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
<!-- 1.serive和dao的对象创建/-->
<bean id="userService" class="service.UserService">
<!--注入userDao对象
name属性:类里面的属性名称
ref属性:创建userDao对象bean标签id值
-->
<property name="userDao" ref="userDaoIm"></property>
</bean>
<bean id="userDaoIm" class="com.spring5.dao.UserDaoIm"></bean>
注意这里是在xml配置文件中放了接口的实现方法类,这就是多态。
注入属性-内部Bean
(1)一对多关系,部门和员工
(2)在实体类中表示1对多的关系,员工表示所属部门,使用对象类型属性表示
//部门类
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
//员工类
private String ename;
private String gender;
private Dpmt dpmt;
public void setDpmt(Dpmt dpmt) {
this.dpmt = dpmt;
}
(3)在spring文件中进行配置
<!--内部bean-->
<bean id="emp" class="com.spring5.bean.Emp">
<!--先设置2个普通属性-->
<property name="ename" value="惠桢"></property>
<property name="gender" value="女"></property>
<!--设置对象属性
1.可以用外部bean的ref代替value去写
2.property中嵌套对象
-->
<property name="dpmt">
<bean id="Dpmt" class="com.spring5.bean.Dpmt">
<property name="dname" value="数据中心"></property>
</bean>
</property>
</bean>
注入属性-级联赋值
(1)第一种写法
<!--级联赋值-->
<bean id="emp" class="com.spring5.bean.Emp">
<!--先设置2个普通属性-->
<property name="ename" value="惠桢"></property>
<property name="gender" value="女"></property>
<!--级联赋值-->
<property name="dpmt" ref="dpmt"></property>
</bean>
<bean id="dpmt" class="com.spring5.bean.Dpmt">
<property name="dname" value=""></property>
</bean>
(2)第二种写法(需要生成对应的get方法,才能设置)
<!--级联赋值-->
<bean id="emp" class="com.spring5.bean.Emp">
<!--先设置2个普通属性-->
<property name="ename" value="惠桢"></property>
<property name="gender" value="女"></property>
<!--级联赋值-->
<property name="dpmt" ref="dpmt"></property>
<property name="dpmt.dname" value="技术部"></property>
</bean>
<bean id="dpmt" class="com.spring5.bean.Dpmt">
<property name="dname" value=""></property>
</bean>
IOC操作Bean管理(XML注入集合属性)
1、注入数组类型属性
2、注入List集合属性
3、注入Map集合属性
4、注入Set集合属性
(1)创建类,定义数组类型、LIst、Map、Set生成对应的set方法。
//1.数组类型属性
private String[] courses;
//2.创建集合list类型属性
private List<String> list;
//3.创建map集合属性
private Map<String,String> maps;
//4.set集合类型属性
private Set<String> sets;
//学生所学多门课程
private List<Course> courseList;
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setCourseList(List<Course> courseList) {
this.courseList = courseList;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
(2)xml配置文件配置
<!--1.集合类型属性的注入-->
<bean id="stu" class="com.spring5.collectiontype.Stu">
<!--数组类型的属性注入
用array标签或list标签都可以
-->
<property name="courses">
<array>
<value>JAVA课程</value>
<value>Mysql课程</value>
</array>
</property>
<!--list类型属性注入-->
<property name="list">
<array>
<value>张三</value>
<value>小三</value>
</array>
</property>
<!--Map类型属性注入-->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="MYSQL" value="mysql"></entry>
</map>
</property>
<!--Set类型属性注入-->
<property name="sets">
<set>
<value>Mysql</value>
<value>Redis</value>
</set>
</property>
<!--注入list集合类型,值是个对象的形式-->
<property name="courseList">
<list>
<ref bean="couser1"></ref>
<ref bean="couser2"></ref>
</list>
</property>
</bean>
<bean id="couser1" class="com.spring5.collectiontype.Course">
<property name="cname" value="Spring5框架课程"></property>
</bean>
<bean id="couser2" class="com.spring5.collectiontype.Course">
<property name="cname" value="Mybatis框架课程"></property>
</bean>
注意:
1)如果集合里是对象
设置属性:
//学生所学多门课程
private List<Course> courseList;
public void setCourses(String[] courses) {
this.courses = courses;
}
XML文件中配置:
<property name="courseList">
<list>
<ref bean="couser1"></ref>
<ref bean="couser2"></ref>
</list>
</property>
</bean>
<bean id="couser1" class="com.spring5.collectiontype.Course">
<property name="cname" value="Spring5框架课程"></property>
</bean>
<bean id="couser2" class="com.spring5.collectiontype.Course">
<property name="cname" value="Mybatis框架课程"></property>
</bean>
2)如何把公共部分提取出来
在spring配置文件中引用命名空间:
xmlns:util="http://www.springframework.org/schema/util"
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
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
使用标签提取:
<!--提取list集合类型属性注入-->
<util:list id="bookList">
<value>样图灵</value>
<value>战术</value>
</util:list>
<!--提取list集合类型属性注入-->
<bean id="book" class="com.spring5.collectiontype.Book" scope="prototype">
<property name="list" ref="bookList"></property>
</bean>
IOC操作Bean管理(FactoryBean)
Spring有两种类型的Bean,一种为普通bean,一种为工厂bean(FactoryBean)
普通Bean:
在配置文件中定义bean的类型就是返回类型
工厂Bean:(了解)
在配置文件中定义bean类型可以喝返回类型不一致
第一步:创建类作为工厂bean,实现接口FactoryBean
第二部:实现接口里面的方法,在实现方法中定义返回的bean类型
public class MyBean implements FactoryBean<Course> {
//定义返回bean对象
@Override
public Course getObject() throws Exception {
Course course=new Course();
course.setCname("测试");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
定义了Mybean,返回的是Course
<bean id="mybean" class="com.spring5.factorybean.MyBean"></bean>
测试类
@Test
public void testmybean()
{
ApplicationContext context=new ClassPathXmlApplicationContext("bean4.xml");
Course course =context.getBean("mybean", Course.class);
System.out.println(course);
}
IOC操作Bean管理(作用域)
1、在spring里,设置bean的实例是单实例还是多实例
2、在Spring里,默认情况下创建的是单实例对象
@Test
public void testBook()
{
ApplicationContext context=new ClassPathXmlApplicationContext("bean3.xml");
Book book1 =context.getBean("book", Book.class);
Book book2 =context.getBean("book", Book.class);
Book book3 =context.getBean("book", Book.class);
System.out.println(book1);
System.out.println(book2);
System.out.println(book3);
}
以上返回的值是同一个地址
3、设置单实例或多实例方法
(1)scope属性值
第一个默认值为singleton,表示单实例
第二个值为prototype
<!--提取list集合类型属性注入-->
<util:list id="bookList">
<value>样图灵</value>
<value>战术</value>
</util:list>
<!--提取list集合类型属性注入-->
<bean id="book" class="com.spring5.collectiontype.Book" scope="prototype">
<property name="list" ref="bookList"></property>
</bean>
4、singleton和prototype的区别
singleton:单实例,加载spring配置文件时就会创建单实例对象
prototype:多实例,不是在加载spring配置时创建对象,当用getBean获取对象时会创建多实例对象。
5、其他值Request和Session
Request:一次请求,会把对象放Request中
Session:一次会话,会把对象放Session中
IOC操作Bean管理(生命周期)
生命周期
概念:从对象创建到销毁的过程
bean的生命周期流程
(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和其他bean的引用(调用set方法)
(3)调用bean的初始化的方法(需要配置)
(4)bean可以使用了(对象获取到了)
(5)当容器关闭时,调用bean的销毁的方法(需要配置)
bean的生命周期的演示
//无参数构造
public Orders()
{
System.out.println("第一步执行无参构造创造bean实例");
}
private String oname;
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步调用set方法设置属性值");
}
//创建执行初始化的方法
public void initMethod()
{
System.out.println("第三步:执行初始化的方法");
}
//创建销毁执行的方法
public void destroyMethod()
{
System.out.println("第五步:创建销毁");
}
<!--3.通过init-method调用初始化方法
4.通过destroymethod调用摧毁方法-->
<bean id="orders" class="com.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="产品"></property>
</bean>
@Test
public void testBean5()
{
// ApplicationContext context=new ClassPathXmlApplicationContext("bean5.xml");
//这里通过修改ApplicationContext为子类接口可执行close方法,否则用子类要强转
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean5.xml");
Orders orders =context.getBean("orders", Orders.class);
//4.第四步:获取创建bean的实例对象
System.out.println(orders);
//手动让bean实例销毁
context.close();
}
测试演示:
bean的后置处理器(bean生命周期有7步)
(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和其他bean的引用(调用set方法)
(3)把bean的实例传给后置处理器的方法
执行方法:postProcessBeforeInitialization
(4)调用bean的初始化的方法(需要配置)
(5)把bean的实例传给后置处理器的方法
执行方法:
(6)bean可以使用了(对象获取到了)
(7)当容器关闭时,调用bean的销毁的方法(需要配置)
bean的后置处理器的演示
(1)创建类,实现接口BeanPostProcessor, 创建后置处理器
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前执行的方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后执行的方法");
return bean;
}
}
(2)在配置文件中配置后置处理器
<!--配置后置处理器(会为所有的bean添加后置处理器)-->
<bean id="mybeanpost" class="com.spring5.bean.MyBeanPost"></bean>
执行效果:
IOC操作Bean管理(xml自动装配)
自动装配(用的少,一般用注解)
根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
演示自动装配过程
(1)根据属性名称自动装配
<!--实现自动装配
bean标签属性autowire,配置自动装配
autowire常用两个值:byName根据属性名称注入 byType根据属性类型注入
特点:需要注入bean的id值必须和类的属性名称一致
-->
<bean id="emp" class="com.spring5.autowire.Emp" autowire="byName">
<!-- <property name="dpmt" ref="dpmt"></property>-->
</bean>
<bean id="dpmt" class="com.spring5.autowire.Dpmt"></bean>
(2)根据属性类型自动注入
把autowire改为byType,相同类型的类不能创建多个
IOC操作Bean管理(引入外部属性文件)
直接配置数据库信息
(1)配置德鲁伊连接池
(2)引入德鲁伊连接池依赖jar包
<!--直接配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/userDb" />
<property name="username" value="root" />
<property name="password" value="admin" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
引入外部属性文件配置数据库连接池
(1)创建外部属性文件,properties格式文件,写数据库信息
(2)把外部的properties属性文件引入spring配置文件中
第一步:在xml配置文件中引入context命名空间
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
第二步:在spring配置文件使用标签引入外部属性文件
<!--引入外部的属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${prop.url}" />
<property name="username" value="${prop.userName}" />
<property name="password" value="${prop.password}" />
<property name="driverClassName" value="${prop.driverClass}" />
</bean>
IOC操作Bean管理(基于注解方式)
注解的概念
(1)注解是代码的特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值)
(2)注解可以作用在类上面、方法上面、属性上面
(3)注解的目的:简化XML配置
Spring针对Bean管理中创建对象提供注解
下面的四个注解功能是一样的,都可以用来创建对象
@Component
@Service
@Controller
@Repository
基于注解方式实现对象创建
1.引入依赖(JAR包)
2.开启组件扫描
目的:告诉spring在哪个类里面要用到注解
<!--开启组件扫描
1.如果要扫描多个包,多个包之间使用逗号隔开
2.扫描上层目录
-->
<context:component-scan base-package="com.spring5"></context:component-scan>
3.创建类,在类上面添加创建对象注解
//在注解里面value属性值可以省略不写
//默认值是类名称,首字母小写
@Component(value = "userService")//相当于bean标签中的id值
public class UserService {
public void add()
{
System.out.println("测试");
}
}
4.开启组件扫描细节配置
<context:component-scan base-package="com.spring5"></context:component-scan>
<!--例子1
use-default-filters="false //表示需要自己配置规则
context:include-filter //设置哪些内容可以扫描
type="annotation" //表示根据注解扫描
expression="org.springframework.stereotype.Controller" //表示只扫描这个包下的Controller注解
-->
<context:component-scan base-package="com.spring5" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--例子2
context:include-filter设置哪些内容不被扫描
expression="org.springframework.stereotype.Controller"表示不扫描带Controller的注解
-->
<context:component-scan base-package="com.spring5">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
基于注解方式实现属性注入
@Autowired
根据属性类型进行自动装配
第一步-创建注解对象
把service和dao的对象创建,在service和dao类添加创建对象注解
第二步-注入
在service中注入dao对象,在service类添加dao类型属性,在属性上面使用注解
@Service(value = "userService")//相当于bean标签中的id值
public class UserService {
//定义dao类型属性
//不需要添加set方法
//添加注入属性注解
@Autowired
private UserDao userDao;
public void add()
{
System.out.println("测试");
userDao.add();
}
}
@Qualifier
根据属性的名称进行注入。这个注解要和Autowired注解一起使用 。
当一个接口下多个实现类时要用具体名称才知道是要调用哪个类
//定义dao类型属性
//不需要添加set方法
//添加注入属性注解
@Autowired
//根据名称进行注入
//对应的接口实现类的value和这个一致
@Qualifier(value = "userDaoIm1")
private UserDao userDao;
@Resource
可以根据类型注入,也可以根据名称注入。
Resource是javax扩展包里的,官方建议不用这个
// @Resource //根据类型进行注入
@Resource(name = "userDaoIm1") //根据名称进行注入
private UserDao userDao;
@Value
注入普通类型属性
@Value(value = "abc")
private String uname;
完全注解开发
(1)创建配置类,替代XML的配置文件
@Configuration //作为配置类
@ComponentScan(basePackages = {"com.spring5"})
public class SpringConfig {
}
(2)编写测试类
@Test
public void testService2()
{
//加载配置类
ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService=context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
这种开发在实际操作中用SpringBoot,其实就是对spring进行整理
AOP(面向切面)
不改源代码进行功能增强的功能
AOP概念
1、什么是AOP?
(1)AOP叫面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合性降低,提高程序的可重用性,同时提高了开发的效率。
(2)不通过修改源代码方式,在主干功能里添加新功能
例子如下:
如果不需要权限判断就可以删除,不需要修改源代码
AOP底层原理
1、AOP底层使用动态代理
(1)有两种情况的动态代理
第一种:有接口的情况,使用jdk动态代理
创建接口实现类代理对象,增强类方法
第二种:没有接口情况,使用CGLIB动态代理
创建子类代理对象,增强类方法
AOP(JDK动态代理)
使用JDK动态代理,使用Proxy类里面的方法创建代理对象
1、调用newProxyInstance方法
方法有三个参数:
第一个参数,类加载器
第二个参数,增强方法所在类,这个类实现的接口,支持多个接口
第三个参数,实现接口InvocationHandler,创建代理对象,写增强的方法
2、编写JDK动态代理代码
(1)创建接口、定义方法
public interface UserDao {
public int add(int a, int b);
public String update(String id);
}
(2)创建接口实现类,实现方法
public class UserDaoIm implements UserDao {
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public String update(String id) {
return id;
}
}
(3)使用Proxy类创建接口代理对象
package com.spring5;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class JDKProxy {
public static void main(String[] args) {
//创建接口实现类的代理对象
Class[] interfaces={UserDao.class};
// Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// return null;
// }
// });
UserDaoIm userDaoIm =new UserDaoIm();
UserDao dao=(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDaoIm));
int result=dao.add(1,2);
System.out.println(result);
}
}
//创建代理对象的代码
class UserDaoProxy implements InvocationHandler{
//1.把创建谁的代理对象,把那个谁传递过来
//有参数的构造进行传递
private Object obj;
public UserDaoProxy(Object obj)
{
this.obj=obj;
}
//增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("在方法之前执行"+method.getName()+":传递的参数"+ Arrays.toString(args));
//被增强的方法执行
Object res=method.invoke(obj,args);
//方法之后
System.out.println("在方法之后执行"+obj);
return res ;
}
}
AOP术语
1、连接点
2、切入点
3、通知(增强)
4、切面
理解概念图如下:
AOP操作(准备工作)
1、Spring框架一般基于AspectJ实现AP相关操作
(1)AspectJ是什么?
AspectJ不是Spring组成部分,是独立AOP框架,一般把AspectK和Spring框架一起使用进行AOP相关操作。
2、基于AspectJ实现AOP操作
(1)基于XML配置文件方式
(2)基于注解方式实现(使用)
3、在项目工程中引入AOP相关依赖
4、切入点表达式
(1)切入点表达作用:知道对哪个类里的哪个方法进行增强
(2)语法结构
execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
(3)
举例1:对com.atguigu.dao.BookDao里面的add进行增强
execution(*com.atguigu.dao.BookDao.add(..))
举例2::对com.atguigu.dao.BookDao里面的所有方法进行增强
execution(*com.atguigu.dao.BookDao.*(..))
举例3:对com.atguigu.dao包里的所有类,和类的所有方法进行增强
execution(*com.atguigu.dao.*.*(..))
AOP操作(AspectJ注解【开发一般用注解】)
创建类和方法
public class User {
public void add()
{
System.out.println("add...");
}
}
创建增强类(编写增强逻辑)
(1)在增强类里面创建方法,让不同的方法代表不同的通知
//增强类
public class UserProxy {
//前置通知
public void before()
{
System.out.println("before...");
}
}
进行通知的配置
(1)在Spring配置文件中开启注解扫描(也可以用完全注解可自己试下)
先引入context和aop的命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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/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">
<!--开启注解扫描-->
<context:component-scan base-package="com.spring5.aopanno"></context:component-scan>
</beans>
(2)使用注解创建User和UserProxy对象
(3)在增强类上加注解@Aspect
//增强类
@Component
@Aspect
public class UserProxy {
//前置通知
public void before()
{
System.out.println("before...");
}
}
(4)在Spring配置文件中开启代理对象
<!--开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
配置不同类型的通知
//增强类
@Component
@Aspect
public class UserProxy {
//前置通知 注意*后有空格
@Before(value = "execution(* com.spring5.aopanno.User.add(..))")
public void before()
{
System.out.println("before...");
}
}
测试类:
@Test
public void testAopAnno()
{
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
User user=context.getBean("user", User.class);
user.add();
}
其他通知类型:
package com.spring5.aopanno;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
//增强类
@Component
@Aspect
public class UserProxy {
//前置通知
@Before(value = "execution(* com.spring5.aopanno.User.add(..))")
public void before()
{
System.out.println("before...");
}
//后置通知(返回通知)
@AfterReturning(value = "execution(* com.spring5.aopanno.User.add(..))")
public void afterReturning()
{
System.out.println("afterRetruning...");
}
//最终通知,有异常也会通知
@After(value = "execution(* com.spring5.aopanno.User.add(..))")
public void after()
{
System.out.println("after...");
}
//异常通知
@AfterThrowing(value = "execution(* com.spring5.aopanno.User.add(..))")
public void afterThrowing()
{
System.out.println("afterThrowing...");
}
//环绕通知:方法前后执行
@Around(value = "execution(* com.spring5.aopanno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("aroundbefore...");
//被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println("aroundafter...");
}
}
相同的切入点抽取
可以发现以上通知的表达式部分都是重复的 ,优点就是如果要改只需要改这一个地方即可
//相同切入点抽取
@Pointcut(value = "execution(* com.spring5.aopanno.User.add(..))")
public void pointDemo()
{
}
//前置通知
@Before(value = "pointDemo()")
public void before()
{
System.out.println("before...");
}
增强类的优先级
多个增强类,对同一个方法进行增强,设置增强类的优先级
在增强类的上面增加注解@Order(数字类型值),数字类型值越小优先级越高,从0开始,0最小
@Component
@Aspect
@Order(1)
public class PerProxy {
//相同切入点抽取
@Pointcut(value = "execution(* com.spring5.aopanno.User.add(..))")
public void pointDemo()
{
}
//前置通知
@Before(value = "pointDemo()")
public void before()
{
System.out.println("Perbefore...");
}
}
### 增强类的优先级
完全使用注解开发
创建配置类,不需要创建xml配置文件
@Configuration
@ComponentScan(basePackages = {"com.spring5"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}
上面的类可以代替下面的XML配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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/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">
<!--开启注解扫描-->
<context:component-scan base-package="com.spring5.aopanno"></context:component-scan>
<!--开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
AOP操作(AspectJ配置文件)
创建类和方法
创建两个类,增强类和被增强类,创建方法
配置文件创建对象
Spring配置文件中创建两个类对象
<!--创建对象-->
<bean id="book" class="com.spring5.aopxml.Book"></bean>
<bean id="bookproxy" class="com.spring5.aopxml.BookProxy"></bean>
配置文件配置切入单
Spring配置文件中配置切入点
<!--配置AOP增强-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="p" expression="execution(* com.spring5.aopxml.Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookproxy">
<!--增强在具体的方法上-->
<aop:before method="before" pointcut-ref="p"></aop:before>
</aop:aspect>
</aop:config>