spring
1、快速入门
// 1、创建一个javabean
package com.spring.bean;
public class Monster {
private Integer monsterId;
private String name;
private String skill;
public Monster(Integer monsterId, String name, String skill) {
this.monsterId = monsterId;
this.name = name;
this.skill = skill;
}
// spring需要一个空构造器
public Monster() {
}
public Integer getMonsterId() {
return monsterId;
}
public void setMonsterId(Integer monsterId) {
this.monsterId = monsterId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
}
@Override
public String toString() {
return "Monster{" +
"monsterId=" + monsterId +
", name='" + name + '\'' +
", skill='" + skill + '\'' +
'}';
}
// 2、创建一个spring 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.spring.bean.Monster" id="monster01"></bean> // 加载JavaBean,在spring中id是唯一的
</beans>
// 2.1 给JavaBean赋值
<bean class="com.spring.bean.Monster" id="monster01">
<property name="monsterId" value="1001"></property>
<property name="name" value="牛魔王!"></property>
<property name="skill" value="芭蕉扇!"></property>
</bean>
// 2.2 添加unit测试类,用于测试
package com.spring.test;
import com.spring.bean.Monster;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringBeanTest {
@Test
public void getMonster() {
// 创建容器 ApplicationContext(接口)
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");// 类加载路径
// 获取对象
// 默认返回Object,运行内存是Monster
//将Object转成Monster,方便用get方法
Monster monster01 = (Monster) ioc.getBean("monster01");
System.out.println(monster01 + "\n" + monster01.getClass());
Monster monster011 = ioc.getBean("monster01", Monster.class);// 直接反射返回Monster对象
}
}
2、类的加载路径
// beanDefinitionNames记载id
String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
3、实现xml配置功能
package com.spring.LouApplicationContext;
import com.spring.bean.Monster;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
public class Application {
private ConcurrentHashMap<String, Object> singletonObject = new ConcurrentHashMap<>();
public Application(String iocBeanXmlFile) throws Exception {
// 类加载路劲
String path = this.getClass().getResource("/").getPath();
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(new File(path + iocBeanXmlFile));
Element rootElement = document.getRootElement();
Element bean = (Element)rootElement.elements("bean").get(0);
String id = bean.attributeValue("id");
String aClass = bean.attributeValue("class");
List<Element> property = bean.elements("property");
Integer monsterId = Integer.parseInt(property.get(0).attributeValue("value"));
String name = property.get(1).attributeValue("value");
String skill = property.get(2).attributeValue("value");
Class<?> aClass1 = Class.forName(aClass);
Monster o = (Monster)aClass1.newInstance();
o.setMonsterId(monsterId);
o.setName(name);
o.setSkill(skill);
singletonObject.put(id, o);
}
public Object getBean(String id){
return singletonObject.get(id);
}
}
4、基于xml配置bean
4.1 通过bean的类型来获取
// 1、通过bean的类型来获取
public void getBeanByType(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
//bean的类型只能是唯一
Monster monster = ioc.getBean(Monster.class);
System.out.println(monster);
}
4.2 通过构造器来配置bean
// 2、通过构造器来配置bean
// 2.1 index来绑定
<bean id="monster03" class="com.spring.bean.Monster">
<constructor-arg value="200" index="0"/>
<constructor-arg value="白骨精" index="1"/>
<constructor-arg value="吸人血" index="2"/>
</bean>
// 2.2 name来绑定
<bean id="monster03" class="com.spring.bean.Monster">
<constructor-arg value="200" name="monsterId"/>
<constructor-arg value="白骨精" name="name"/>
<constructor-arg value="吸人血" name="skill"/>
</bean>
// 2.3 通过构造器变量的数据类型,来绑定构造器(构造器有多个,但是变量类型不能相同)
<bean id="monster05" class="com.spring.bean.Monster">
<constructor-arg value="200" type="java.lang.Integer"/>
<constructor-arg value="白骨精" type="java.lang.String"/>
<constructor-arg value="吸人血" type="java.lang.String"/>
</bean>
4.3 通过p名称来配置bean
// 3、通过p名称来配置bean
<bean id="monster06" class="com.spring.bean.Monster"
p:monsterId="500"
p:name="红孩儿"
p:skill="吐火"
/>
4.4 通过ref来配置
// 4、通过ref来配置
<!--// 配置MemberDAOImpl对象-->
<bean class="com.spring.dao.MemberDAOImpl" id="memberDAO"/>
<!-- 配置MemberServiceImpl对象-->
<bean class="com.spring.service.MemberServiceImpl" id="memberService">
<!--
ref="memberDAO"表示,引用的对象是id=memberDAO的对象
-->
<property name="memberDAO" ref="memberDAO"/>
</bean>
package com.spring.service;
import com.spring.dao.MemberDAOImpl;
public class MemberServiceImpl {
private MemberDAOImpl memberDAO;
public MemberDAOImpl getMemberDAO() {
return memberDAO;
}
public void setMemberDAO(MemberDAOImpl memberDAO) {
this.memberDAO = memberDAO;
}
public void add(){
memberDAO.add();
}
}
4.5 通过内部bean来配置属性
// 5、通过内部bean来配置属性
<bean class="com.spring.service.MemberServiceImpl" id="memberService2">
<property name="memberDAO">
<bean class="com.spring.dao.MemberDAOImpl"/>
</property>
</bean>
4.6 对集合/数组类型属性进行赋值
// 6、对集合/数组类型属性进行赋值
// 6.1 定义master类
package com.spring.bean;
import java.util.*;
public class Master {
private String name;
private List<Monster> monsterList;
private Map<String, Monster> monsterMap;
private Set<Monster> monsterSet;
// 数组
private String[] monsterName;
private Properties pros;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Monster> getMonsterList() {
return monsterList;
}
public void setMonsterList(List<Monster> monsterList) {
this.monsterList = monsterList;
}
public Map<String, Monster> getMonsterMap() {
return monsterMap;
}
public void setMonsterMap(Map<String, Monster> monsterMap) {
this.monsterMap = monsterMap;
}
public Set<Monster> getMonsterSet() {
return monsterSet;
}
public void setMonsterSet(Set<Monster> monsterSet) {
this.monsterSet = monsterSet;
}
public String[] getMonsterName() {
return monsterName;
}
public void setMonsterName(String[] monsterName) {
this.monsterName = monsterName;
}
public Properties getPros() {
return pros;
}
public void setPros(Properties pros) {
this.pros = pros;
}
@Override
public String toString() {
return "Master{" +
"name='" + name + '\'' +
", monsterList=" + monsterList +
", monsterMap=" + monsterMap +
", monsterSet=" + monsterSet +
", monsterName=" + Arrays.toString(monsterName) +
", pros=" + pros +
'}';
}
}
// 6.2 定义xml文件
<bean class="com.spring.bean.Master" id="master">
<property name="name" value="太上老君"/>
<property name="monsterList">
<list>
<ref bean="monster01"/>
<ref bean="monster03"/>
// 定义内部bean
<bean class="com.spring.bean.Monster">
<property name="name" value="黄袍怪"/>
<property name="skill" value="杀人"/>
<property name="monsterId" value="100"/>
</bean>
</list>
</property>
</bean>
4.7 对集合/数组类型属性进行赋值
// 1、数组类型属性进行赋值
<list>
<ref bean="monster01"/>
<ref bean="monster03"/>
<bean class="com.spring.bean.Monster">
<property name="name" value="黄袍怪"/>
<property name="skill" value="杀人"/>
<property name="monsterId" value="100"/>
</bean>
</list>
// 2、集合方式进行赋值
<property name="monsterMap">
<map>
<entry>
<key>
<value>monster001</value>
</key>
<ref bean="monster03"/>
</entry>
<entry>
<key>
<value>monster002</value>
</key>
<ref bean="monster01"/>
</entry>
</map>
</property>
4.8 set属性赋值
// 对象直接依赖注入
<property name="monsterSet">
<set>
<ref bean="monster04"/>
<ref bean="monster01"/>
</set>
</property>
4.9 Array属性赋值
// 字符串可以直接赋值
<property name="monsterName">
<array>
<value>小妖怪</value>
<value>老妖怪</value>
</array>
</property>
4.10 Properties赋值
// key-value进行存放,以字符串的形式(财产的意思)
<property name="pros">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
<prop key="ip">127.0.0.1</prop>
</props>
</property>
4.11 util创建list
// 提高数据的复用性
<util:list id="myBookList">
<value>三国演义</value>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
</util:list>
<bean class="com.spring.bean.BookStore" id="bookStore">
<property name="bookList" ref="myBookList"/>
</bean>
4.12 级联属性赋值
<bean class="com.spring.bean.Dept" id="dept"/>
<bean class="com.spring.bean.Emp" id="emp">
<property name="name" value="jack"/>
<property name="dept" ref="dept"/>
<!--级联属性赋值,调用dept.setName方法-->
<property name="dept.name" value="Java开发部门"/>
</bean>
4.13 beanfactory获取bean
<!--
1、通过静态工厂获取
2、class是静态工厂的全路径
3、factory-method表示指定静态工厂类的哪个方法返回对象
4、value是指定返回静态工厂的哪个对象
-->
<bean id="my_monster01" class="com.spring.factory.MyStaticFactory" factory-method="getMonster">
<constructor-arg value="monster02"/>
</bean>
package com.spring.factory;
import com.spring.bean.Monster;
import java.util.HashMap;
import java.util.Map;
public class MyStaticFactory {
private static Map<String, Monster> monsterMap;
//使用static代码块进行初始化
static {
monsterMap = new HashMap<>();
monsterMap.put("monster01",new Monster(100,"牛魔王","芭蕉扇"));
monsterMap.put("monster01",new Monster(102,"狐狸精","好看"));
}
//返回一个对象,单类模式
public static Monster getMonster(String key){
return monsterMap.get(key);
}
}
4.14 InstanceFactory实例工厂
// 1、定义一个实例工厂类
package com.spring.factory;
import com.spring.bean.Monster;
import java.util.HashMap;
import java.util.Map;
public class MyInstanceFactory {
private Map<String, Monster> monster_Map;
// 通过普通代码块进行初始化,每次初始化类的时候,都会执行一次
{
monster_Map = new HashMap<>();
monster_Map.put("monster03", new Monster(300, "牛魔王", "芭蕉扇"));
monster_Map.put("monster04", new Monster(400, "狐狸精", "好看"));
}
// 写一个方法返回Monster对象
public Monster getMonster(String key) {
return monster_Map.get(key);
}
}
// 2、配置xml文件
<!--
1、配置monster对象,实例工厂
2、factory-bean指定哪个实例工厂对象的返回bean
3、factory-method表示指定静态工厂类的哪个方法返回对象
-->
<bean class="com.spring.factory.MyInstanceFactory" id="myInstanceFactory"/>
<bean id="my_monster02" factory-bean="myInstanceFactory" factory-method="getMonster">
<constructor-arg value="monster03"/>
</bean>
4.15 FactoryBean获取bean
package com.spring.factory;
import com.spring.bean.Monster;
import org.springframework.beans.factory.FactoryBean;
import java.util.HashMap;
import java.util.Map;
public class MyFactoryBean implements FactoryBean {
private String key;
private Map<String, Monster> monster_Map;
{
monster_Map = new HashMap<>();
monster_Map.put("monster03", new Monster(300, "牛魔王", "芭蕉扇"));
monster_Map.put("monster04", new Monster(400, "狐狸精", "好看"));
}
@Override
public Object getObject() throws Exception {
return monster_Map.get(key);
}
public void setKey(String key) {
this.key = key;
}
@Override
public Class<?> getObjectType() {
return Monster.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
// xml文件配置
<bean id="my_monster05" class="com.spring.factory.MyFactoryBean">
<property name="key" value="monster04"/>
</bean>
4.16 Extend Bean
// Extend
<bean id="monster10" class="com.spring.bean.Monster">
<property name="name" value="蜈蚣精"/>
<property name="monsterId" value="1000"/>
<property name="skill" value="蜇人"/>
</bean>
<bean id="monster11" class="com.spring.bean.Monster" parent="monster10"/>
// tips
<!--
1、如果被指定abstract,表示该bean对象,适用于继承
2、这个bean不能被被实例化
-->
<bean id="monster12" class="com.spring.bean.Monster" abstract="true"/>
4.17 Bean的单类和多类
scope 范围
<!--
1、在默认情况下,属性是单类。scope
2、在ioc中,只有一个bean对象
3、getBean时,返回的是同一个对象
4、返回一个新的Bean对象,则可以scope="property"
-->
<bean id="cat" class="com.spring.bean.Cat" scope="singleton">
<property name="id" value="100"/>
<property name="name" value="小花猫"/>
</bean>
// scope="singleton" lazy-init="true" 此时,不会预先加载对象(ioc内不会存在),getBean才会
// 默认懒加载是关闭的
<bean id="cat" class="com.spring.bean.Cat" scope="singleton" lazy-init="true">
<property name="id" value="100"/>
<property name="name" value="小花猫"/>
</bean>
5、bean的生命周期
bean对象是由jvm完成
package com.spring.bean;
public class House {
private String name;
public House() {
}
public House(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("set方法" + name);
}
public void init(){
System.out.println("house init()");
}
public void destroy(){
System.out.println("house destroy");
}
}
<!--
1、init-method指定初始化方法,在setter方法后执行
2、方法执行的时机,由spring容器控制
3、destroy-method="" 容器关闭的时候触发
-->
<bean class="com.spring.bean.House" id="house" init-method="init" destroy-method="destroy">
<property name="name" value="北京"/>
</bean>
6、bean的后置处理器
// 创建处理器,必须实现接口implements BeanPostProcessor
package com.spring.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
// 在bean的init方法前被调用(xml文件配置的init方法)
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization().. bean=" + bean + beanName);
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization().. bean=" + bean + beanName);
return null;
}
}
// xml文件配置
<bean class="com.spring.bean.House" id="house" init-method="init" destroy-method="destroy">
<property name="name" value="豪宅"/>
</bean>
<!--配置后置处理器对象
1、当我们在bean02.xml容器配置文件,配置了MyBeanPostProcessor
2、后置处理器,就会作用在该容器的所有对象
-->
<bean class="com.spring.bean.MyBeanPostProcessor" id="MyBeanPostProcessor"/>
7、属性文件配置
// 配置文件赋值bean
<!--配置文件配置bean
1、指定配置文件 location
-->
<context:property-placeholder location="classpath:my.properties"/>
<bean class="com.spring.bean.Monster" id="monster1000">
<property name="monsterId" value="${monsterId}"/>
<property name="name" value="${name}"/>
<property name="skill" value="${skill}"/>
</bean>
my.properties
monsterId=1000
name=jack (中文的话,转成unicode编码)
skill=hello
8、自动装配
<bean class="com.spring.dao.OrderDao" id="orderDao"/>
<!--配置OrderService对象
1、autowire="byType"表示在创建orderService时,通过类型的方式,给对象属性自动完成赋值
2、orderService中有private OrderDao orderDao
3、就会在容器中找有没有OrderDao类型对象
4、不能同时有两个,相同类型的对象
-->
<bean autowire="byType" class="com.spring.service.OrderService" id="orderService"/>
<bean autowire="byType" class="com.spring.web.OrderAction" id="orderAction"/>
9、注解配置bean
1、Component 表示注解标识的是一个组件
2、Controller 表示当前注解标识是一个控制器,通常用于Servlet
3、Service 表示当前注解标识的是一个处理业务逻辑的类,通常用于Servlet类
4、Repository 表示当前注解标识的是一个持久化层的类,通常用于Dao类
9.1 快速入门
// 持久化层的类
@Repository
public class UserDao {
}
// 业务逻辑
@Service
public class UserService {
}
// 控制器
@Controller
public class UserAction {
}
// 标识为组件
@Component
public class MyComponent {
}
// xml配置
<context:component-scan base-package="com.spring.component"/>
9.2 自己实现注解bean
// 1、创建注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
String value() default "";
}
// 2、创建注解加载配置文件
package com.spring.annotation;
@ComponentScan(value = "com.spring.component")
public class LouSpringConfig {
}
// 3、创建SpringApplicationContext
public class LouSpringApplicationContext {
private Class configClass;
private final ConcurrentHashMap<String, Object> ioc = new ConcurrentHashMap<>();
public LouSpringApplicationContext(Class configClass) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
this.configClass = configClass;
// 1、得到LouSpringConfig 配置的@ComponentScan(value = "com.spring.annotation")
ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
String path = componentScan.value();
System.out.println("要扫描的包=" + path);
// 得到类的加载器
ClassLoader classLoader = LouSpringApplicationContext.class.getClassLoader();
// 替换一下路径里面的.
//path = path.replace(".", "/");
//System.out.println(path);
URL resource = classLoader.getResource("com/spring/component");
System.out.println("URL=" + resource);
// 将要加载的资源路径下的文件,进行遍历
File file = new File(resource.getFile());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
//System.out.println("========");
//System.out.println(f.getAbsolutePath());
String fileAbsolutePath = f.getAbsolutePath();
if (fileAbsolutePath.endsWith(".class")) {
String className =
fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
String classFullName = path + "." + className;
System.out.println(classFullName);
// 判断该类是不是需要注入容器
Class<?> aClass = classLoader.loadClass(classFullName);
if (aClass.isAnnotationPresent(Component.class) ||
aClass.isAnnotationPresent(Controller.class) ||
aClass.isAnnotationPresent(Service.class) ||
aClass.isAnnotationPresent(Repository.class)
) {
// 完整的反射一个类
Class<?> aClass1 = Class.forName(classFullName);
Object instance = aClass1.newInstance();
ioc.put(StringUtils.uncapitalize(className), instance);
}
}
}
}
}
public Object getBean(String name){
return ioc.get(name);
}
}
10、自动装配
// 自动加载userService类
public class UserAction {
@Autowired
private UserService userService;
public void sayOk(){
System.out.println("UserAction sayOK");
userService.hi();
}
}
// @Resource
@Controller
public class UserAction {
// @Resource(name = "userService")表示装配id=userService 对象
@Resource(name = "userService")
private UserService userService400;
public void sayOk(){
System.out.println("UserAction sayOK");
userService400.hi();
}
}
11、动态代理
# 动态代理,核心代码
package com.spring.proxy2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class VehicleProxyProvider {
private Vehicle target_vehicle;
public VehicleProxyProvider(Vehicle target_vehicle) {
this.target_vehicle = target_vehicle;
}
public Vehicle getProxy(){
ClassLoader classLoader = target_vehicle.getClass().getClassLoader();
Class<?>[] interfaces = target_vehicle.getClass().getInterfaces();
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("交通工具开始运行了");
Object result = method.invoke(target_vehicle, args);
System.out.println("交通工具停止运行了");
return result;
}
};
//public static Object newProxyInstance(ClassLoader loader,
// Class<?>[] interfaces,
// InvocationHandler h)
Vehicle proxy = (Vehicle)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return proxy;
}
}