spring IOC和AOP简介
Spring
IOC
IOC(接口)
1. IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
2. Spring提供IOC容器实现两种方式:(两个接口)
1. BeanFactory:IOC容器最基本的实现方式,是Spring内部的使用接口,不提供开发人员进行使用 在配置文件时不会创建对象,获取对象的时候才会去创建对象
2. ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用 加载配置文件时就会把配置文件对象进行创建
3. ApplicationContext接口有实现类 1.FileSystemXmlApplicationContext(绝对路径) 2.ClassPathXmlApplicationContext(src下文件)
Bean管理
1. 什么是Bean管理,Bean管理指的是两个操作
1. Spring创建对象
2. Spring注入属性
2. Bean管理操作两种方式
1. 基于XML配置文件方式实现
2. 基于注解方式实现
基于xml文件配置
-
通过set方法注入
<bean id="book" class="com.original.spring5.Book"> <property name="name" value="asd"></property> <property name="id" value="1"></property> </bean> -
通过有参构造
<bean id="orders" class="com.original.spring5.Orders"> <constructor-arg name="name" value="asd"></constructor-arg> <constructor-arg name="address" value="XiAn"></constructor-arg> </bean> -
p名称空间注入
使用p名称空间注入,可以简化基于xml配置方式- 添加约束
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">- 注册bean
<bean id="book" class="com.original.spring5.Book" p:id="11" p:name="pname"></bean> -
xml注入其它类型的属性
-
注入属性字面量
- null值
<bean id="book" class="com.original.spring5.Book"> <property name="name" value="asd"></property> <property name="id" value="1"></property> <property name="address"> <null/> </property> </bean>- 属性值包含特殊符号
1.把<>转义 > 2.把带特殊符号的写进CDATA <![DATA[]]> <property name="address"> <value> <![CDATA[<<南靖>>]]> </value> </property> -
注入属性-外部bean
public class UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void add() { userDao.add(); } } // dao public class UserDaoImpl implements UserDao { @Override public void add() { System.out.println("UserDaoImpl add"); } } // xml 配置 <bean id="userService" class="com.original.service.UserService"> <property name="userDao" ref="userDaoImpl"></property> </bean> <bean id="userDaoImpl" class="com.original.dao.impl.UserDaoImpl"> </bean> -
注入属性-内部bean
- 一对多关系:部门和员工,一个部门有多个员工,一个员工属于一个部门
@Setter @ToString public class Dept { private String dname; } @Setter @ToString public class Emp { private String name; private String gender; private Dept dept; } <!-- 内部bean的操作 --> <bean id="emp" class="com.original.model.Emp"> <!-- 设置两个普通属性 --> <property name="name" value="xiaocao"></property> <property name="gender" value="woman"></property> <!-- 对象属性类型 可以ref也可以内部创建bean --> <property name="dept"> <bean id="dept" class="com.original.model.Dept"> <property name="dname" value="开发部"></property> </bean> </property> </bean> -
注入属性-级联赋值
- 第一种写法
<!-- 内部bean的操作 --> <bean id="emp" class="com.original.model.Emp"> <!-- 设置两个普通属性 --> <property name="name" value="xiaocao"></property> <property name="gender" value="woman"></property> <!-- 级联赋值 --> <property name="dept" ref="dept"> </property> </bean> <bean id="dept" class="com.original.model.Dept"> <property name="dname" value="财务部"></property> </bean>- 第二种写法 - 依赖emp中dept的get方法
<bean id="emp" class="com.original.model.Emp"> <!-- 设置两个普通属性 --> <property name="name" value="xiaocao"></property> <property name="gender" value="woman"></property> <!-- 级联赋值 --> <property name="dept" ref="dept"></property> <property name="dept.dname" value="技术部"></property> </bean> <bean id="dept" class="com.original.model.Dept"> <property name="dname" value="财务部"></property> </bean>
-
-
IOC操作Bean管理(xml注入集合属性)
- 注入数组类型属性
- 注入List集合属性
- 注入Map集合类型属性
- Set
- 在集合里面设置对象属性值
- 把集合注入部分提取出来
<?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:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd"> <!-- 提取list集合属性类型注入 --> <util:list id="bookList"> <value>易筋经</value> <value>易筋经2</value> <value>易筋经3</value> </util:list> <bean id="book" class="com.original.base.collectiontype.Book"> <property name="list" ref="bookList"></property> </bean> </beans> -
IOC操作Bean管理(FactoryBean)
- Spring有两种类型bean,一种普通bean,另外一种工厂bean(FactoryBean)
- 普通bean:在配置文件中定义bean类型就是返回类型
- 工厂bean:在配置文件定义bean类型和返回类型不一样
- 第一步创建类,让这个类作为工厂bean,实现接口FactoryBean
- 实现接口里面的方法没在实现的方法中定义返回的bean类型
-
IOC操作Bean管理(bean作用域)
- 在Spring里面,设置创建bean实例是单实例还是多实例
- 在Spring里面,默认情况下,我们创建的bean是单实例
- 如何设置单实例还是多实例
- 在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
- 默认值 singleton 单实例
- prototype 多实例
- singleton和prototype区别
- singleton 单实例, prototype多实例
- 设置scope值是singleton时候,加载spring配置文件时候就会创建单实例对象
- 设置scope值是prototype时候,不是在加载spring配置文件的时候创建bean,是在调用getBean方法时创建
- Request 基本不用 一次请求
- Session 基本不用 一次会话
-
IOC操作Bean管理(bean生命周期)
- 生命周期
- 从对象的创建到对象销毁的过程
- bean生命周期
- 通过构造器创建bean实例(无参构造)
- 为bean的属性设置值和对其他bean引用(调用set方法)
- 调用bean的初始化的方法(需要进行配置初始化的方法)
- bean可以使用了(对象获取到了)
- 当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
public class Orders { public Orders() { System.out.println("第一步,调用无参构造创建bean实例"); } private String oname; public void setOname(String oname) { System.out.println("set 方法设置属性值"); this.oname = oname; } public void initMethod() { System.out.println("第三部 执行初始化方法"); } public void destoryMethod() { System.out.println("第五步 执行销毁的方法"); } } <bean id="orders" class="com.original.bean.Orders" init-method="initMethod" destroy-method="destoryMethod"> <property name="oname" value="手机"></property> </bean> @Test public void test() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml"); Orders orders = applicationContext.getBean("orders", Orders.class); System.out.println("获取bean对象"); ((ClassPathXmlApplicationContext) applicationContext).close(); } - bean的后置处理器,总共七步
- 通过构造器创建bean实例(无参构造)
- 为bean的属性设置值和对其他bean引用(调用set方法)
- 把bean的实例传递bean后置处理器的方法 postProcessAfterInitialization
- 调用bean的初始化的方法(需要进行配置初始化的方法)
- 把bean的实例传递bean后置处理器的方法 postProcessBeforeInitialization
- bean可以使用了(对象获取到了)
- 当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
- 后置处理器的实现
- 创建类,实现接口BeanPostProcessor,创建后置处理器
public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("初始化之前 postProcessAfterInitialization"); return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName); } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("初始化之后 postProcessBeforeInitialization"); return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName); } }- xml中配置bean
<!-- 配置后置处理器 --> <bean id="myBeanPost" class="com.original.bean.MyBeanPostProcessor"></bean>
- 生命周期
-
操作bean管理(xml自动装配)
- 什么是自动装配
- 根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
- xml中配置自动装配
<!-- 配置自动装配 autowire属性: 1. byName 根据属性名称注入,注入值bean的id值和类属性名称一致 2. byType 根据属性类型注入,多个类型bean存在时,就会出现问题,相同类型的bean不能定义多个 --> <bean id="emp" class="com.original.demo.autowire.Emp" autowire="byType"> <!-- <property name="dept" ref="dept"></property> --> </bean> <bean id="dept" class="com.original.demo.autowire.Dept"></bean>
- 什么是自动装配
-
IOC操作bean管理(外部属性文件)
- 直接配置数据库信息
- 配置德鲁伊连接池
- 引入德鲁伊连接池
- 引入外部属性文件配置数据库连接池
- 创建外部属性文件,写入数据库连接信息
prop.driverClass=com.mysql.jdbc.Driver prop.url=jdbc:mysql://localhost:3306/userdb prop.username=root prop.password=root- 把外部properties属性文件引入到bean.xml中
- 引入context命名空间
xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd- 完整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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 直接配置连接池 --> <!-- <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/userdb"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean> --> <!-- 引入外部properties文件 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 配置连接池 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${prop.driverClass}"></property> <property name="url" value="${prop.url}"></property> <property name="username" value="${prop.username}"></property> <property name="password" value="${prop.password}"></property> </bean> </beans>
- 直接配置数据库信息
-
IOC操作bean管理(基于注解方式)
- 什么是注解
- 注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值...)
- 使用注解,注解在类上面、属性方面、方法上面
- 使用注解目的:简化xml配置
- Spring针对Bean管理中创建对象提供注解,下面四个注解功能是一样的,都可以用来创建bean实例
- @Component
- @Service
- @Controller
- @Repository
- 基于注解方式完成对象创建
- 开启组件扫描 xml配置方式
<!-- 如果配置多个包,多个包之间可以用逗号隔开 --> <context:component-scan base-package="com.original"></context:component-scan>- 创建类,在类上添加注解 @Component(value="userService") // value等价于xml方式的id,省略默认为首字母小写
- 开启组件扫描的细节配置
- use-default-filters="false" 关闭默认扫描规则
<!-- 设置那些内容进行扫描 --> <context:component-scan base-package="com.original" use-default-filters="false"> <context:include-filter type="annotation" expression="" /> </context:component-scan> <!-- 设置哪些内容不进行扫描 这个不需要关闭默认规则--> <context:component-scan base-package="com.original"> <context:excluder-filter type="annotation" expression="" /> </context:component-scan>
- use-default-filters="false" 关闭默认扫描规则
- 基于注解方式实现属性注入
- @AutoWired:根据属性类型进行自动装备
- 创建对象,在Service 和 Dao上加上注解
- @Qualifier:根据属性名称进行注入
- 这个注解的属性,和上面@Autowired一起使用
@Autowired // 根据类型注入 @Qualifier(value = "userDaoImpl") - @Resource:可以根据类型注入,可以根据名称注入 - javax提供的
// 根据类型注入 // @Resource // 根据名称注入 @Resource(name = "userDaoImpl") private UserDao userDao;- @Vaule:注入普通类型属性
@Value(value = "abc") private String name; - @AutoWired:根据属性类型进行自动装备
- 完全注解开发
- 创建配置类,替代xml配置文件
@Configuration // 作为配置类,替代xml配置文件 @ComponentScan(basePackages = { "com.original" }) public class SpringConfig { } // 测试类AnnotationConfigApplicationContext ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
- 什么是注解
AOP
动态代理
1. 有两种情况动态代理
1. 有接口情况,使用JDK动态代理,创建接口实现类代理对象,增强类的方法
Proxy对象,调用newProxyInstance方法
方法有三个参数
1. 类加载器
2. 增强方法所在的类,这个类实现的接口,支持多个接口
3. 实现这个接口InvocathonHandler,创建代理对象,写增强方法
代码实现:
1. 创建业务代码接口
```
public interface ProxyTestDao {
int add(int a, int b);
String update(String id);
}
```
2. 实现接口
```
public class ProxyTestDaoImpl implements ProxyTestDao {
@Override
public int add(int a, int b) {
// TODO Auto-generated method stub
return a + b;
}
@Override
public String update(String id) {
// TODO Auto-generated method stub
return id;
}
}
```
3. 实现InvocathonHandler接口,创建代理对象
```
// 创建代理对象代码
class OwnerProxy implements InvocationHandler {
// 1. 创建的是谁的代理对象,需要把谁传过来
private Object obj;
// 有参数的构造
public OwnerProxy(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;
}
}
```
4. 调用
```
public class JDKProxy {
public static void main(String[] args) {
// 创建接口代理类代理对象
// 写匿名内部类或者实现接口InvocationHandler
Class[] interfaces = { ProxyTestDao.class };
ProxyTestDaoImpl impl = new ProxyTestDaoImpl();
ProxyTestDao dao = (ProxyTestDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces,
new OwnerProxy(impl));
int res = dao.add(1, 2);
System.out.println("end :" + res);
}
}
```
2. 没接口情况,使用CGLIB动态代理,CGLIB创建当前类子类的代理对象
- AOP 术语
- 连接点:一些类里面哪些类可以被增强,这些方法称为连接点
- 切入点:实际被真正增强的方法,称为切入点
- 通知(增强):实际增强的逻辑部分称为通知,通知有多种类型
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知
- 切面:是动作,把通知应用到切入点过程
- AOP 操作
- Spring框架一般都是基于AspectJ实现AOP操作
- AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作
- 基于AspectJ实现AOP操作
- 基于xml配置文件
- 基于注解方式实现(使用)
- 引入AspectJ依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8.RC2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.4</version>
</dependency>
- 切入点表达式
- 切入点表达式作用:知道对哪个类里面的哪个方法进行增强
- 语法结构:execution([权限修饰符][返回类型][类全路径]方法名称) 举例
- 对com.original.dao.UserDao类里面的add方法进行增强
execution(*com.original.dao.UserDao.add(..))- 对com.original.dao.UserDao类里面的所有方法进行增强
execution(*com.original.dao.UserDao.*(..))- 对com.original.dao包里面的所有类所有方法
execution(*com.original.dao.*.*(..))
- AOP操作(AspectJ注解)
- 创建类,在类里面定义方法
public class User { public void add() { System.out.println("user add"); } }- 创建增强类(编写增强逻辑)在增强类里面创建方法,不同的方法代表不同的通知
public class UserProxy { // 前置通知 public void before() { System.out.println("before......"); } }- 进行通知的配置
- 在spring配置文件中,开启注解扫描
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="com.original.aop.ano"></context:component-scan> </beans>- 使用注解创建User和UserProxy对象
- 在增强类上面添加注解@Aspect
- 在spring配置文件中生成代理对象
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>- 配置不同类型的通知
- 在增强类里面,在作为通知方法上面
@Component @Aspect public class UserProxy { // 前置通知 @Before(value = "execution(* com.original.aop.ano.User.add(..))") public void before() { System.out.println("before......"); } // 最终通知 @After(value = "execution(* com.original.aop.ano.User.add(..))") public void after() { System.out.println("after......"); } // 后置通知(返回通知) @AfterReturning(value = "execution(* com.original.aop.ano.User.add(..))") public void afterReturning() { System.out.println("AfterReturning......"); } // 异常通知 @AfterThrowing(value = "execution(* com.original.aop.ano.User.add(..))") public void afterThrowing() { System.out.println("AfterThrowing......"); } // 环绕通知 @Around(value = "execution(* com.original.aop.ano.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前......"); // 被增强的方法 proceedingJoinPoint.proceed(); System.out.println("环绕之后......"); } } - 公共切入点抽取
@Pointcut(value = "execution(* com.original.aop.ano.User.add(..))") public void pointdemo() { } // 前置通知 @Before(value = "pointdemo()") public void before() { System.out.println("before......"); }- 有多个增强类对同一个方法增强,设置优先级
- 在增强类上面添加注解Order(值)值越高优先级越高 @Order(1)
- xml 方式 (省略)

浙公网安备 33010602011771号