文章目录
IOC底层原理
主要用到的技术
xml解析、工厂模式、反射
IOC接口BeanFactory
1、IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
2、Spring提供IOC容器实现的两种方式:(两个接口)
(1)、BeanFactory:IOC容器基本实现,是spring内部的使用接口,不提倡开发人员使用
特点:加载配置文件的时候不会创建对象,在获取对象(使用才去创建对象)
(2)、ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用
特点:加载配置文件的时候会把在配置文件配置的对象进行创建
(3)、ApplicationContext接口的两个实现类:
IOC操作Bean管理(基于xml)
1、什么是Ben管理
Bean管理指的两个操作:
(1)、Spring创建对象
在Spring配置文件中,使用bean标签,标签中添加对应属性,就可以创建对象,下面介绍常用的
id属性:唯一标识
class属性:类的全限定类名
创建对象时,默认是执行无参构造方法
(2)、Spring注入属性
set注入
<bean id="user" class="com.yun.User">
<property name="nickname" value="张三"/>
<property name="password" value="123456"/>
</bean>
有参构造注入
<bean id="user" class="com.yun.User">
<constructor-arg name="nickname" value="猪八戒" type="java.lang.String"/>
<constructor-arg name="password" value="zhubajie" type="java.lang.String"/>
</bean>
P名称空间注入(可以简化xml配置)
导入约束:
<beans>
<bean id="user" class="com.yun.User" p:nickname="孙悟空" p:password="sunwukong"/>
</beans>
注入null值和特殊符号
<beans>
<bean id="user" class="com.yun.User">
<property name="nickname" value="张三"/>
<property name="password" value="123456"/>
<property name="address">
<null/>
</property>
</bean>
</beans>
<beans>
<bean id="user" class="com.yun.User">
<property name="nickname" value="张三"/>
<property name="password" value="123456"/>
<property name="address">
<value><![CDATA[<<重庆市渝北区>>]]></value>
</property>
</bean>
</beans>
注入属性-外部bean
<bean name="userDaoImpl" class="com.yun.dao.UserDaoImpl"/>
<bean name="userService" class="com.yun.service.UserService">
<property name="userDao" ref="userDaoImpl"/>
</bean>
注入属性-内部bean
<beans>
<bean id="emp" class="com.yun.bean.Emp">
<property name="ename" value="jack"/>
<property name="sex" value="23"/>
<property name="dept">
<bean id="dept" class="com.yun.bean.Dept">
<property name="dname" value="研发部"/>
</bean>
</property>
</bean>
</beans>
注入属性-级联赋值
第一种方式
<beans>
<bean id="emp" class="com.yun.bean.Emp">
<property name="ename" value="jack"/>
<property name="sex" value="23"/>
<!--级联赋值-->
<property name="dept" ref="dept"/>
</bean>
<bean id="dept" class="com.yun.bean.Dept">
<property name="dname" value="运营部"/>
</bean>
</beans>
第二种方式
<beans>
<bean id="emp" class="com.yun.bean.Emp">
<property name="ename" value="jack"/>
<property name="sex" value="23"/>
<!--级联赋值-->
<property name="dept" ref="dept"/>
<property name="dept.dname" value="人事部"/>
</bean>
<bean id="dept" class="com.yun.bean.Dept"/>
</beans>
注入数组、List、Map、Set类型属性
<beans>
<bean id="stu" class="com.yun.bean.Stu">
<!--注入数组属性-->
<property name="sourses">
<array>
<value type="java.lang.String">123</value>
<value type="java.lang.String">456</value>
<value type="java.lang.String">789</value>
</array>
</property>
<!--注入List属性-->
<property name="lists">
<list value-type="java.lang.String">
<value>jack</value>
<value>lusi</value>
<value>lili</value>
</list>
</property>
<!--注入Map属性-->
<property name="maps">
<map key-type="java.lang.String" value-type="java.lang.String">
<entry key="m1" value="m_1"/>
<entry key="m2" value="m_2"/>
<entry key="m3" value="m_3"/>
</map>
</property>
<!--注入Set属性-->
<property name="sets">
<set value-type="java.lang.String">
<value>23</value>
<value>21</value>
<value>19</value>
<value>193</value>
<value>223</value>
</set>
</property>
</bean>
</beans>
在List集合中设置对象类型值
<beans>
<bean id="stu" class="com.yun.bean.Stu">
<!--注入数组属性-->
<property name="sourses">
<array>
<value type="java.lang.String">123</value>
<value type="java.lang.String">456</value>
<value type="java.lang.String">789</value>
</array>
</property>
<!--注入List属性-->
<property name="lists">
<list value-type="java.lang.String">
<value>jack</value>
<value>lusi</value>
<value>lili</value>
</list>
</property>
<!--注入Map属性-->
<property name="maps">
<map key-type="java.lang.String" value-type="java.lang.String">
<entry key="m1" value="m_1"/>
<entry key="m2" value="m_2"/>
<entry key="m3" value="m_3"/>
</map>
</property>
<!--注入Set属性-->
<property name="sets">
<set value-type="java.lang.String">
<value>23</value>
<value>21</value>
<value>19</value>
<value>193</value>
<value>223</value>
</set>
</property>
<!--注入list集合类型,值是对象-->
<property name="courseList">
<list>
<ref bean="course1"/>
<ref bean="course2"/>
</list>
</property>
</bean>
<!-- list集合中的对象 -->
<bean id="course1" class="com.yun.bean.Course">
<property name="cname" value="spring框架"/>
</bean>
<bean id="course2" class="com.yun.bean.Course">
<property name="cname" value="Mybatis框架"/>
</bean>
</beans>
把List注入部分提前出来
<!-- 提取list集合类型属性注入 -->
<util:list id="bookList">
<value>平凡的世界</value>
<value>时间简史</value>
<value>十万个为什么</value>
</util:list>
<!-- 提取list集合类型属性注入使用 -->
<beans>
<bean id="book" class="com.yun.bean.Book">
<property name="lists" ref="bookList"/>
</bean>
</beans>
IOC操作Bean管理
1、Spring有两种bean,一种是普通bean,另一种是工厂bean(FactoryBean)
2、普通bean:在配置文件中定义什么类型的bean就返回什么类型的bean
3、工厂bean:在配置文件中定义bean类型可能跟返回类型不一样
第一步创建类,并实现接口FactoryBean
第二部实现接口里面的方法,在实现的方法中定义返回的bean类型
IOC操作Bean管理(bean的作用域)
1、在Spring里面,设置创建bean实例是单实例还是多实例
2、在Spring里面,默认创建的是单实例bean及默认Spring配置文件中,在创建bean时隐式scope=“singleton”
3、配置多实例
Spring配置文件中,在创建bean时指定scope=“prototype”即可
4、singleton与prototypetype区别
(1)、singleton为单实例、prototype为多实例
(2)、设置scope值为singleon时,加载Spring配置文件时就会创建单实例对象
设置scope值为prototype时,不是在加载Spring配置文件时创建对象,而是在调用getBean方法是创建多实例对象
5、scope的可配值:singleton、prototype、request(每次创建对象时,会把对象放在request中)、session(每次创建对象时,会把对象放在session中)
IOC操作Bean管理(bean的生命周期)
1、什么是生命周期
从对象创建到对象销毁的过程
2、bean生命周期
第一步执行无参构造创建bean实例
第二步调用set方法为对象属性赋值
第三步在初始化之前执行后置处理方法postProcessBeforeInitialization(Object bean, String beanName)
第三步执行初始化方法
第五步在初始化之后执行后置处理方法postProcessAfterInitialization(Object bean, String beanName)
第六步获取对象实例
第七步执行销毁的方法
3、bean生命周期演示
IOC操作Bean管理(xml自动装配)
1、什么是自动装配
根据指定装配规则(属性名称或属性类型),Spring自动将匹配的属性值进行注入
2、演示自动装配
IOC操作Bean管理(xml中引用外部属性文件)
1、直接配置数据库连接信息
<!--直接配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc://localhost:3306/userDb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
2、引入外部属性文件配置数据库连接池
创建外部属性文件,properties格式文件,写入数据库信息
prop.driverClassName=com.mysql.jdbc.Driver
prop.url=jdbc://localhost:3306/userDb
prop.username=root
prop.password=root
把外部properties属性文件引入到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"
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">
</beans>
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClassName}"/>
<property name="url" value="${prop.url}"/>
<property name="username" value="${prop.username}"/>
<property name="password" value="${prop.password}"/>
</bean>
IOC操作Bean管理(基于注解方式)
1、Spring针对Bean管理中创建对象提供的注解
(1)、@Component
(2)、@Service
(3)、@Controller
(4)、@Repository
以上的四个注解功能都是一样的。
AOP底层原理
1、AOP底层使用动态代理(有 两种代理模式)
第一种有接口,使用jdk动态代理
创建接口实现类代理对象,增强类的方法
第二种没有接口,使用CGLB动态代理
创建子类的代理对象,增强类的方法
AOP(JDK动态代理)
1、使用JDK动态代理,使用Proxy类里面的方法创建代理对象
调用newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 方法
参数说明:
第一个参数:ClassLoader 类加载器
第二个参数:代理类实现的接口列表
第三个参数:实现这个接口InvocationHandler ,创建代理对象,写增强部分
2、编写JDK动态代理代码
(1)、创建接口,定义方法
public interface UserDao {
int add(int a,int b);
String update(String userId);
}
(2)、创建接口的实现类,实现方法
public class UserDaoImpl implements UserDao {
@Override
public int add(int a, int b) {
System.out.println("执行了add()方法......");
return a+b;
}
@Override
public String update(String userId) {
return userId;
}
}
(3)、使用Proxy类创建接口代理对象
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
UserDaoImpl userDaoImpl = new UserDaoImpl();
UserDao userDao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDaoImpl));
int result = userDao.add(1, 2);
System.out.println(result);
}
}
class UserDaoProxy implements InvocationHandler{
//创建的是谁的代理对象,把谁传过来
private Object object;
public UserDaoProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法执行前
System.out.println("方法执行前...方法名:"+method.getName()+"::方法参数:"+ Arrays.toString(args));
//被增强的方法
Object res = method.invoke(object, args);
//方法执行后
System.out.println("方法执行后......"+res);
return res;
}
}
运行结果:
AOP(术语)
1、连接点
类里面那些方法可以被增强,这些方法称为连接点
2、切入点
实例被真正增强的方法,称为切入点
3、通知(增强)
(1)实际增强的逻辑部分称为通知(增强)
(2)通知有多种类型
前置通知 -->方法执行前执行
后置通知 -->方法执行后执行
环绕通知 -->方法执行的前后都执行
异常通知 -->方法执行异常时执行
最终通知 -->同finally
4、切入点表达式
作用:知道对那个类里面的那个方法进行增强
语法结构:
execution([权限修饰符][返回值类型][类的全限定名][方法名称]([参数列表]))
返回值类型可以省略不写、
([参数列表])—> (…):任意个参数
其余可以用 * 号占位 表示全部
5、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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
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">
<!-- 扫描有@Aspect注解的类 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.yun.aopanno"></context:component-scan>
</beans>
6、演示实例
@Component
public class User {
public void add(){
// int i = 10/0;
System.out.println("add......");
}
}
@Component
@Aspect
public class UserProxy {
//前置通知
@Before(value = "execution(* com.yun.aopanno.User.add(..))")
public void before(){
System.out.println("before.....");
}
//最终通知
@After(value = "execution(* com.yun.aopanno.User.add(..))")
public void after(){
System.out.println("after.....");
}
//后置通知 在方法有返回值后执行
@AfterReturning(value = "execution(* com.yun.aopanno.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning.....");
}
//异常通知
@AfterThrowing(value = "execution(* com.yun.aopanno.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing.....");
}
//环绕通知
@Around(value = "execution(* com.yun.aopanno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前.....");
Object proceed = proceedingJoinPoint.proceed();
System.out.println("环绕后.....");
}
}
7、抽取相同的切入点
@Component
@Aspect
public class UserProxy {
@Pointcut(value = "execution(* com.yun.aopanno.User.add(..))")
public void pointDemo(){
}
//前置通知
@Before("pointDemo()")
public void before(){
System.out.println("before.....");
}
//最终通知
@After("pointDemo()")
public void after(){
System.out.println("after.....");
}
//后置通知 在方法有返回值后执行
@AfterReturning(value = "pointDemo()")
public void afterReturning(){
System.out.println("afterReturning.....");
}
//异常通知
@AfterThrowing(value = "pointDemo()")
public void afterThrowing(){
System.out.println("afterThrowing.....");
}
//环绕通知
@Around(value = "pointDemo()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前.....");
Object proceed = proceedingJoinPoint.proceed();
System.out.println("环绕后.....");
}
}
8、有多个增强类对同一个方法进行增强,设置增强类优先级
(1)、在增强类上面添加注解@Order(数字类型值),数字类型值悦小优先级越高
@Component
@Aspect
@Order(1)
public class PersonProxy {
@Before(value = "execution(* com.yun.aopanno.User.add(..))")
public void before(){
System.out.println("Person before......");
}
}
JdbcTemplate(概论和准备)
1、什么是JdbcTemplate
(1)、Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库的操作
2、准备工作