一.SpringDI/IOC
1.SpringDI
DI:(中文依赖注入):是对IOC概念的不同角度的描述。
主要是指应用程序在运行时,每一个bean对象都依赖IOC容器注入当前bean对象所需要的另外一个bean对象。
作用:胶水,帮助springIOC容器,把所有依赖关系的javaBean对象粘合在一起。
实现步骤:
1.提供set方法
1.1提供set方法
2.配置标签
2.1set注入
<property 属性名="属性值"></property>
属性:
name=====>属性名
value=====>属性值
ref======>属性值的引用
实现方式:
1.set注入
2.构造注入
3.属性注入(不用)
4.注解注入
支持的数据类型:
1.基本类型与String
2.JavaBean对象注入(三层调用)
3.复杂类型
具体实现:set注入
package com.itheima.service;
import com.itheima.dao.IUserDao;
import com.itheima.dao.UserDaoImp;
public class UserServiceImp implements IUserService {
IUserDao userDao;
public UserServiceImp(UserDaoImp userDao) {
this.userDao = userDao;
}
public UserServiceImp() {
}
// public void setUserDao(IUserDao userDao){
// this.userDao = userDao;
//}
public void save() {
System.out.println("===service的新增===");
userDao.save();
}
}
package com.itheima.dao;
public class UserDaoImp implements IUserDao {
public void save() {
System.out.println("===dao的新增===");
}
}
package com.itheima.controller;
import com.itheima.service.IUserService;
import com.itheima.service.UserServiceImp;
public class UserControllerImp implements IUserController {
IUserService service;
public UserControllerImp(UserServiceImp service) {
this.service = service;
}
public UserControllerImp() {}
// public void setService(IUserService service){
// this.service = service;
// }
public void save() {
System.out.println("===controller的新增===");
service.save();
}
}
<!--1.set注入-->
<!-- <bean id="dao" class="com.itheima.dao.UserDaoImp"></bean>-->
<!-- <bean id="service" class="com.itheima.service.UserServiceImp">-->
<!-- <property name="userDao" ref="dao"></property>-->
<!-- </bean>-->
<!-- <bean id="controller" class="com.itheima.controller.UserControllerImp">-->
<!-- <property name="service" ref="service"></property>-->
<!-- </bean>-->
构造注入
<!-- 构造注入 -->
<!-- <bean id="dao1" class="com.itheima.dao.UserDaoImp"></bean>-->
<!-- <bean id="service1" class="com.itheima.service.UserServiceImp">-->
<!-- <constructor-arg name="userDao" ref="dao1"></constructor-arg>-->
<!-- </bean>-->
<!-- <bean id="controller1" class="com.itheima.controller.UserControllerImp">-->
<!-- <constructor-arg name="service" ref="service1"></constructor-arg>-->
<!-- </bean>-->
三层代码同上
2.SpingIOC-管理bean
bean的创建
1.通过反射调用类的无参构造方法(默认)。
2.通过指定的工厂,创建bean对象。
Delphi
<!-- <bean id="singer1" class="com.itheima.pojo.Singer1" factory-bean="factory" factory-method="createSinger"></bean>-->
<!-- <bean id="factory" class="com.itheima.factory.SingerFactory"></bean>-->
package com.itheima.factory;
import com.itheima.pojo.Singer;
import com.itheima.pojo.Singer1;
public class SingerFactory {
// 创建对象
public Singer1 createSinger(){
System.out.println("执行工厂方法");
return new Singer1();
}
}
3.通过作用的指定的静态工厂,创建bean对象。
Delphi
<bean id="singer2" class="com.itheima.factory.SingerStaticFactory" factory-method="createSinger" scope="prototype"></bean>
package com.itheima.factory;
import com.itheima.pojo.Singer;
import com.itheima.pojo.Singer1;
public class SingerStaticFactory {
// 创建对象
public static Singer1 createSinger(){
System.out.println("===>执行static工厂的工厂方法");
return new Singer1();
}
}
bean的作用域
含义 :bean的创建方式
语法:<bean scope = ''属性值''></bean>
属性值:
singleton单例(默认)
prototype多例
request请求
session会话
bean的生命周期
1.实例化:创建对象
2.初始化:
2.1接口初始化
2.2属性初始化
具体实现
Delphi
package com.itheima.pojo;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
// initializingBean接口
// DisposableBean接口
@Component
public class Teacher implements InitializingBean, DisposableBean {
//实例化
public Teacher() {
System.out.println("===>生命周期:实例化");
}
//初始化(接口)
public void afterPropertiesSet() throws Exception {
System.out.println("===>生命周期:初始化1(接口)");
}
//销毁了(接口)
public void destroy() throws Exception {
System.out.println("===>生命周期:销毁了1(接口)");
}
// 第二种初始化销毁方法
//初始化(属性)
@PostConstruct
public void doinit() throws Exception {
System.out.println("===>生命周期:初始化2(属性)");
}
//销毁了(属性)
@PreDestroy
public void dodestory() throws Exception {
System.out.println("===>生命周期:销毁了2(属性)");
}
}
<!-- <bean id="teacher" class="com.itheima.pojo.Teacher" init-method="doinit" destroy-method="dodestory"></bean>-->
3.操作使用
4.销毁了(实现同上)
4.1接口销毁了
4.2属性销毁了
3.Spring的配置(第一种纯xml的忽略)
1.spring2.5前==xml ----第一天案例
2.spring2.5后==xml+annotation ----Spring_Day02
3.spring3.0后==annotation+javaConfig配置类 ----Spring_Day02
注意:spring 2.5后=xml+annotation
目的优化一下代码:
<bean id="" class="" init-method="" destroy-method="" scope="" autowire="">
<property></property>
<constructor-arg></constructor-arg>
</bean>
1.spring配置---第二种------spring2.5后==xml+annotation
注解:
注入类
替换:<bean id="" class=""></bean>
位置:类
语法:@Component(value="注入容器中的id,如果省略id为类名且首字母小写,value属性名可以省略")
举例:
<bean id="user" class="com.apsourse.包.User"></bean>
||等价于||
@Component
Class User{}
注意:不能单独使用,配合扫描使用
<context:component-scan base-pageage=""><</context:component-scan>>
@Repository=====>注入数据访问层
@Service=======>注入业务层
Controller=======> 注入控制层
以上第三个注解与@Component功能语法一致
注入数据
@ value
含义:注入基本数据与String
替换:<property></property>
修饰:成员变量
语法:@Value("数据内容")
@Value("${动态获取}")
注意:不能单独用,配合加载配置文件标签
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
@Autowired
语法:@Autowired(required="true-默认,false,是否必须进行装配")
修饰:成员变量
含义:注入javaBean
注意:
1.默认是按照类型装配,如果容器中有多个类型,则会自动切换为名称装配
2.默认是按照类型装配,如果容器中有多个类型,则自动切换为名称装配,若名称也没有与之对应则会报异常NoUniqueBeanDefinitionException
3.默认是按照类型装配,如果容器中没有一个 类可以与之匹配,则会报异常NoSuchBeanDefinitionException
其他注解:
@Primary
含义:首选项,当类型冲突的情况下,此注解修饰的类被列为首选
修饰:类
注意:不能单独使用,必须与@Component...联合使用
@Qualifier(value="名称")
含义:按照名称装配
修饰:成员变量
注意:不能单独使用,必须与@Autowired联合使用
@Resource(name="名称")
含义:按照名称装配
修饰:成员变量
注意:单独使用
@Scope
含义:配置类的作用域
修饰:类
注意:不能单独使用,必须与@Component...联合使用
@Scope("prototype")
@Scope("singleton")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Scope(ConfigurableBeanFactory.SCOPE.SINGLETON)
@PostConstruct:初始化,替换init-method
@PreDestroy:销毁,替换destory-method
2.Spring配置---第三种(替代applicationContext.xml)文件------spring2.5后==>xml+annotation
@Configuration
作用:指定当前类是一个配置类
细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写
@ComponentScan
作用:用于通过注解指定spring在创建容器时要扫描的包
替换:<context:component-scan base-package=""></context:component-scan>
@PropertySource
作用:用于指定properties文件的位置
替换:<context:property-placeholder location=""></context:property-placeholder>
@Import
作用:用于导入其他的配置类
属性:value:用汉语指定其他配置类的字节码
例子:@Import(SystemSpringConfig.class)
@Bean
作用:用于把当前方法的返回值作为bean对象存入spring的容器中
属性:name:用于指定bean的id,当不写时候,默认值时当前方法的名称
二.动态代理
* 基于接口的动态代理: * 特点:字节码随用随创建,随用随加载 * 作用:不修改源码的基础上对方法增强 * 涉及的类:Proxy * 提供者:JDK官方 * 如何创建代理对象: * 使用Proxy类中的newProxyInstance方法 * 创建代理对象的要求: * 被代理类最少实现一个接口,如果没有则不能使用 * newProxyInstance方法的参数: * ClassLoader:类加载器 * 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。 * Class[]:字节码数组 * 它是用于让代理对象和被代理对象有相同方法。固定写法。 * InvocationHandler:用于提供增强的代码
* Object proxy=====》被代理对象的引用===(蔡徐坤对象) * Method method====》执行的方法========(蔡徐坤唱歌方法) * Object[] args====》执行方法的参数=====(蔡徐坤唱歌方法的参数) * Object===========》执行方法的返回值===(蔡徐坤唱歌方法的返回值) * */ * 作用:执行被代理对象的任何接口方法都会经过该方法 * 方法参数的含义 * proxy 代理对象的引用 * method 当前执行的方法 * args 当前执行方法所需的参数 * Object 和被代理对象方法有相同的返回值 */ /* 第一个参数:ZhouSeenImpl.class.getClassLoader() 表示类加载器(ClassLoader),用于加载动态生成的代理类 通常使用被代理类的类加载器,保证类加载的一致性 第二个参数:ZhouSeenImpl.class.getInterfaces() 表示被代理类实现的所有接口数组 动态代理技术要求必须基于接口实现,代理对象会实现这些接口中定义的方法 这里会返回ZhouSeenImpl类所实现的所有接口(包括ISinger) 第三个参数:new InvocationHandler() 这是一个接口实现,用于定义代理逻辑 其中的invoke()方法会拦截所有对代理对象方法的调用 可以在该方法中实现增强逻辑(如日志记录、性能监控、事务控制等),再决定是否调用原始对象的方法 */
com.itheima.cglibtest.ISinger iSinger = (ISinger) Proxy.newProxyInstance(ZhouSeenImpl.class.getClassLoader(), ZhouSeenImpl.class.getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object obj = null; if (method.getName().equals("song")) { System.out.println("跳一段舞"); obj = method.invoke(new ZhouSeenImpl(), args); } if (method.getName().equals("sing")) { System.out.println("打一个篮球"); obj = method.invoke(new ZhouSeenImpl(), args); } return obj; } }); iSinger.song();