1.AOP:控制反转,把创建对象的过程交给Spring容器
2.IOC:面向切面编程,不改源代码进行功能增强
bean.xml文件
<bean id = "昵称" class = "类的全类名" ></bean>
测试
1.加载spring配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");//src下的可以直接这样扫描 2.得到配置的对象 类名 昵称= context.getBean("bean中ID",类名.class); 3.调用bean中对象类中的方法 昵称.method();
IOC容器:
(1)IOC底层原理
(2)IOC接口(BeanFactory)
(3)IOC操作Bean管理(注解与xml)
控制反转-->对象的创建与对象调度都交给spring管理
(1):...
------> 原始模式(耦合度高)
------>工厂模式
------>IOC过程
IOC(接口)
IOC思想基于IOC容器,底层是对象工厂
Spring提供IOC容器实现的两种方式(两个接口)加载配置文件,获取配置创建对象
(1)BeanFactory:spring内置接口,不提供给开发人员使用。
加载配置文件时 不创建对象,获取(使用)对象的时候才会创建对象----getBean("");
(2)ApplicationContext:上面的子接口,功能更强,开发人员使用
加载即创建。
(3)ApplicationContext接口的实现类
IOC操作Bean管理
(1)xml
(2)注解
创建对象时默认执行无参构造方法
xml方式注入属性:
(1)DI:依赖注入(ioc的一种具体实现)
1. set方法注入:
//在类中生成set方法
<bean id = "" class =""> <!-- name:类中属性名称 value:向属性中注入的值 --> <property name = "" value =""></property> </bean>
2. 有参注入:
//在类中生成有参构造方法
<bean id ="" class = ""> <constructor-arg name = "" value =""> </contructor-arg> </bean>
p 名称空间注入
(1)用于简化xml配置
//添加p名称空间 xmlns:p="http://www.springframework.org/schema/p" //set注入属性 <bean id = "" class = "" p:属性名 = "属性值" > </bean>
xml注入其他类型:
null: <property name =""> <null/> </property> 特殊符号: <property name ="" > <value> < <![CDATA[****]]>> </value> </property>
注入属性-外部bean
(1)创建两个类 service 和 mapper
(2) service 调用 mapper
<!-- ref 就是将外部的bean注入进来-->
注入属性-内部bean和级联赋值
(1)一对多
(2)实体类中表示一对多关系
<!-- emp 对象-->
<bean id = "emp" class = "">
<!-- emp的属性和dept对象属性--> <property name = "" value = ""> </property> <property name = "dept" > <bean id = "dept" class = "">
<property name = "" value = ""></property>
</bean> <property>
</bean>
---------------------------------------------------内部bean
注入属性-级联赋值1
<!-- emp 对象--> <bean id = "emp" class = ""> <!-- emp的属性和dept对象属性--> <property name = "" value = ""> </property> <property name = "dept" ref = "dept"></property> <!--外部bean 级联赋值--> </bean> <bean id = "dept" class = ""> <property name = "" value = ""><property> </bean>
注入属性-级联赋值2(猜测比外部级联优先级高)
<!-- emp 对象 生成一下getDept方法--> <bean id = "emp" class = ""> <!-- emp的属性和dept对象属性--> <property name = "" value = ""> </property> <property name = "dept" ref = "dept"></property> <property name = "dept.dname" value= ""></property> <!--外部bean 级联赋值--> </bean> <bean id = "dept" class = ""> <property name = "" value = ""><property> </bean>
xml注入集合属性:
<!-- 数组--> <bean ...> <property name = "course"> <array> <value>...</value> ...... </array> </property> <!-- map --> <property name = "maps"> <map> <entry key = "" value = ""> </entry> ...... </map> </property> <!-- list--> <property name = "list"> <list> <value>...</value> ...... </list> </property> <!-- set--> <property name = "list"> <set> <value>...</value> ...... </set> </property>
注入集合对象2
<!-- 注入list集合类型 ,值是对象--> <property name = "courseList"> <list> <ref bean = "" ></ref> </list> </property> <!--创建多个course对象--> <bean 1> <property/> .... <bean 2> <property/> ....
把集合注入部分提取出来:
引入名称空间util
<util:list id = "bookList"> <value></value> <value></value> </util:list> <bean id = "book " class = ""> <property name = '"' ref = "bookList"></> </>
IOC操作bean管理(FactoryBean)
1. 普通bean
2.FactoryBean (定义bean类型与返回类型可以不同)
第一步 :创建类 ,作为工厂bean ,实现FactoryBean 。
第二步 :实现接口里面的方法,在实现方法中定义返回的bean类型
public class MyBean implements FactoryBean<Course>{ //定义返回Bean public Course getObject () throws Exception{ new Course();-->course course.setCname("...."); return course; } public Class<?> getObjectType() { return null; } public boolean isSingleton () { return false; } } -------------------------------------------------------------------- <bean id = "myBean" class = ""></bean> ..... context.getBean("myBean", Course.class); --->course
bean的作用域:
通过scope属性的值来设置:
scope = "singleton"(默认) 加载配置文件时就会创建单实例对象
prototype:多实例 调用getBean方法时创建多实例对象
request:一次请求
session:一次会话
bean的生命周期:
(1)无参构造创建bean实例
(2)为bean的属性设置值,对其他bean的引入(调用set方法)
(3)把bean实例传递给bean后置处理器postProcessBeforeInitialization方法
(3)调用bean的初始化的方法
(4)把bean实例传递给bean后置处理器postProcessAfterInitialization方法
(4)使用bean
(5)容器关闭时,调用bean的销毁方法。
//在类中创建初始化方法 init () 和 销毁方法 destroy() <bean id = "" class = "" init-method = "init " destroy-method = "destroy">
<property></>
</bean>
..........
contex.close();
ApplicationContext接口中没有close方法
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext ();
添加后置处理器:
(1)创建类 MyBeanPost,实现BeanPostProcessor接口
(2)实现其中两个方法
<!-- 配置后置处理器 为配置文件中所有bean实例创建后置处理器--> <bean id = "myBeanPost" class = "....MyBeanPost">
xml自动装配:
根据指定装配规则(属性名称 属性类型),Spring指定将匹配的属性值进行注入
autowire = "byName";byType;
byName 注入值bean得id值与类的属性名称一致
外部属性文件:
1.创建外部属性文件
2. 在配置文件中添加context命名空间
<!-- 引入外部文件--> <context:property-placeholder location ="classpath:jdbc.properties" > <!-- 配置连接池--> <bean id="dataSource"class="com.alibaba.druid.pool.DruidDataSource"> <property name = "driverClassName" value"${prop.driverClass}"></property> ..... </bean>
IOC注解
Spring针对bean管理中创建对象提供的注解:
(1)@Component
(2)@Service
(3)@Controller
(4)@Repository
基于注解实现对象创建
第一步 引入依赖
第二步 开启组件扫描<context>
多个包之间 逗号隔开(扫描上层目录也行)
<context:component-scan base-package = " "></context:component-scan>
第三步 创建类 在类上添加注解
//自定义配置filter <context : component-scan base-package = "" use-default-filters = "false"> <context : include-filter type = "annotation" expression = "org.springframework.stereotype.Controller"/> </>
exclude-filter type 不扫描哪些内容
注解实现属性注入:
(1)@AutoWired :根据属性类型注入
(2)@Qualifier:根据属性名称注入
根据类型注入,一个借口可能有多个实现类,可以在AutoWired 下添加Qualifier(value ="userDaoImpl1")
(3)@Resource:都行
如果要根据名称注入 Resource(name = "")
(4)@Value:注入普通类型属性
为定义的属性赋值
service中定义dao类型属性,是由于spring的设计思想是利用java的多态特性 减少耦合
完全注解开发:
配置类:SpringConfig
@Configuration
@Component(basePackages ={""})
SpringConfig
加载配置类
new AnnotationConfigApplicationContext(SpringConfig.class);-->ApplicationContext
AOP(底层动态代理)
不改源代码,增加新功能
动态代理:
(1)有接口:创建接口实现类代理对象,增强类方法
(2)没有接口:创建类的子类代理对象
1.JDK动态代理,使用Proxy类里面的方法创建代理对象
调用nexProxyInstance方法
参数一:类加载器
参数二:增强方法所在的类,这个类实现的接口,支持多个接口
参数三:实现这个接口InvocationHandler,创建代理对象,写增强部分的代码
public class JDKProxy{ psvm{ <!-- 创建接口实现类代理对象--> Class [] interfaces = {UserDao.class}; UserDaoImpl userDao = new UserDaoImpl(); Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new InvocationHandler(){ public Object invoke (Object proxy,Method method,Object[] args) throws Throwable{ return null; } } ); ------------------------------------------------------------------------- UserDao dao =Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDapProxy(userDao) ); } } //创建代理对象代码 class UserDaoProxy implements InvocationHandler{ //把创建的是谁的代理对象,就把谁传递过来 //有参构造传递 private Object obj; public UserDaoProxy(Oject obj){ this.obj = obj; } public Object invoke (Object proxy,Method method,Object[] args) throws Throwable{ Onject res = method.invoke(obj,args); return res; } }
Aop(术语)
1.连接点:可以被增强的方法
2.切入点:实际被增强的方法
3.通知(增强):增加的部分逻辑
前置通知 后置通知 环绕通知 异常通知 最终通知
4.切面
把通知应用到切入点的过程
基于AspectJ实现AOP操作
独立的AOP框架
切入点表达式
作用:知道哪个类里面的哪个方法进行增强
execution([权限修饰符] [返回类型][全类名][方法名称]([参数列表]))
AspectJ注解
(1)xml中添加context,aop命名空间,开启注解扫描
(2)使用注解创建User和UserProxy对象
(3)增强类上加注解@Aspect 生成代理对象
(4)开启Aspect生成代理对象
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
@Component @Aspect public class UserProxy{
//前置通知 @Before(value = "execution(*org.xxx.User.add(..))") public void before(){ System.out.println("...."); } }
@After(value = "")最终通知
@AfterReturning(value = "")后置通知 (返回通知)有异常不执行
@Around(value = "")环绕通知 参数为 ProceedingJoinPoint proceedingJoinPoint
sout 前
proceedingJoinPoint.proceed();
sout 后
@AfterThrowing(value = "")异常通知
抽取相同的切入点
@Pointcut(value = "execution(*org.xxx.User.add(..))")
public void pointdemo(){
}
@Before (value = "pointdemo()")
多个增强类对一个方法进行增强:优先级
增强类上加一个注解@Order(数值类型放入值)值小优先级高
配置文件做AspectJ
<!-- 配置AOP增强--> <aop:config> <!-- 切入点--> <aop:pointcut id = "p" expression = "execution(*org.xxx.Book.Buy(..))"/> <!-- 配置切面--> <aop :aspect ref = "bookProxy"> <!--增强作用在具体的方法上--> <aop:before method = "before" pointcut-ref = "p" > </aop:aspect> </aop:config> <bean id ="book" class = ""></> <bean id ="bookProxy" class = "">
@EnableAspectJAutoProxy(proxyTargetClass = true)