wordpress建站比较,建设网站的价值,2021年中国关键词,政工网站建设spring框架
spring是轻量级的容器框架
spring framework
1、Spring核心学习内容 IOC、AOp, jdbcTemplate,声明式事务 2、IOC:控制反转#xff0c;孚以管理部8号对象 3.AOP:切面编程4.JDBCTemplate:是spring提供一套访问数据库的技术,应用性强#xff0c;相对好理解5.声明式…spring框架
spring是轻量级的容器框架
spring framework
1、Spring核心学习内容 IOC、AOp, jdbcTemplate,声明式事务 2、IOC:控制反转孚以管理部8号对象 3.AOP:切面编程4.JDBCTemplate:是spring提供一套访问数据库的技术,应用性强相对好理解5.声明式事务:基于ioc/aop实现事务管理理解有需要小伙伴花时间6.IOC, AOP 是重点同时难点
重要概念
1.Spring可以整合其他的框架(老韩解读: Spring是管理框架的框架)
2.Spring有两个核心的概念: IOC 和 AOP 3.IOC [Inversion Of Control反转控制]。传统的开发模式[JdbcUtils/反射]程序----环境//程序读取环境配置然后自己创建对象
1.spring根据配置文件xml注解,创建对象,并放入容器中,并且可以完成对象之间的依赖.
spring可以整合其他框架,是管理其他框架的框架
spring中有两个核心概念:ioc控制反转 aop 切面编程文件
在传统开发中:程序读取环境配置信息{可能会用到new,或者反射}然后自己创建对象
在ioc开发模式:容器中创建好对象----被程序使用
容器创建对象的方法:1.xml配置文件,2.注解
1.spring根据配置文件或者配置文件创建对象,并放入到容器中;并完成对象之间的依赖
2.当需要某个对象实例的时候,可以直接从容器中获取
3.编写人员可以更加关注对象完成相应的业务
4.DI{dependency injection}依赖注入
5.Spring最大的价值,通过配置提供给程序使用
实例
package com.Test;import com.bean.Monster;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** Author: zs* Description: TODO* DateTime: 2024/9/9 13:56**/
public class MonsterTest {Testpublic void getMonster() {//创建容器ApplicationContext//该容器和容器配置文件关联//建议用接口接收,ApplicationContext ioc new ClassPathXmlApplicationContext(beans.xml);//拿到容器是为拿到容器关联配置文件中的Java对象//可以通过getbean获取对应的对象,通过id,默认返回的类型是object,运行类型是monster/*这里的运行类型可以改为monter,因为getclass方法获取到该对象的运行类型为monterObject monster01 ioc.getBean(monster01);*/Monster monster01 (Monster) ioc.getBean(monster01);//完成向下转型之后可以分别获取属性//输出System.out.println(monster01 monster01 monster01.getClass());System.out.println(monster01.getName()monster01.getSkill()monster01.getMonsterid());System.out.println(ok);//可以在获取的时候直接指定class类型Monster monster2 ioc.getBean(monster01, Monster.class);System.out.println(monster2.getName()monster2.getSkill()monster2.getMonsterid());}
}
配置文件编写
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
!-- 配置monster对象Javabean--
!-- 在beans中可以配置多个bean--!--bean表示一个对象--
!-- class创建Java对象类的全路径--
!-- Spring 底层使用反射创建的--
!-- id表示Java对象在spring容器中的id,通过id可获得对象 id是唯一的--
!-- property namename value牛哈/用于给对象属性赋值,如果不改就是默认值--bean classcom.bean.Monster idmonster01property namemonsterid value100/property namename value牛哈/property nameskill value叫//bean
!-- 完成Java对象的创建--/beanspackage com.bean;/*** Author: zs* Description: TODO* DateTime: 2024/9/9 13:26**/
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;}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;}}classpathxmlapplicationcontext 为什么可以读取到beans.xml public void classPath() {File file new File(this.getClass().getResource(/).getPath());System.out.println(file);//结果 /*D:\javaprogram\Spring\out\production\Spring*///读取路径是out目录}debug时会发现:beandefinitionmap会保存类的信息,但是不创建对象
当需要对象时,通过反射创建对象时用;
IOC容器
底层机制
当代码执行到 ApplicationContext ioc new ClassPathXmlApplicationContext(beans.xml);时,容器已经创建完毕 在beanfactory下的beandefinitionmap中就会保存配置文件中的信息,通过集合的方式 大小512 图一 ConcurrentHashMap类型时集合,存bean节点配置信息 在beanDefinitionMap中有属性table table为数组 类型为ConcurrentHashMap$node 因为是数组类型,可以存放很多bean对象信息,就是bean.xml配置文件 初始化为512, 会自动扩容 图二 通过hash算法monster01对象信息就保存在index 217 位置 保存是以 ConcurrentHashMap$node类型 key值就是beans.xml文件中的id值 value 就是monster01对象的[属性/属性值/是否为懒加载] 属性值保存在propertyValueList,就是记录monster01对象的属性值 beandefinitionmap只保存了类信息,并不保存对象
类的对象用concurrenthashmap$node的类型保存,类型为基于泛型的,
因为保存类的对象时,会默认为单例所以存在这个位置 在beanfactory中的另一个属性singletonObjects 类型为concurrentHashMap 其中有个属性table 类型是concurrenthashmap$node 如果在beans.xml文件中配置的对象时单例的 就是初始化放在里边 当我们getbean(“id”)时,首先会在底层查beandifinitionmap中按照id 名字查询是为单例,如果为单例会在singletonobject[类似单例池的作用]查找并返回,若不是单例会通过动态反射机制创建一个对象放进去. 为了方便我们快速查找定位,直接存入id[就是在beans.xml文件中配置的bean的名称]值, 如果先查看自己定义了多少对象,通过beandefinitionnames方法查找 //查看容器注入了那些bean对象 输出bean的idString[] beanDefinitionNames ioc.getBeanDefinitionNames();for(String beanDefinitionName : beanDefinitionNames) {System.out.println(beanDefinitionName);}原理模拟
手动开发一个简单的spring基于XML配置的程序
第一步引入jar包{dom4j}
xml文件用的是上边的deans.xml
类的代码
package com.applicationcontext;import com.bean.Monster;
import com.sun.org.apache.bcel.internal.generic.NEW;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;import java.io.File;
import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;/*** Author: zs* Description: 实现spring的一个简单容器* 实现bean.xml文件的解析,并生成容器* DateTime: 2024/9/10 12:09**/
public class ApplicationContext {private ConcurrentHashMapString, Object singletonobject new ConcurrentHashMap();//构造器//接收一个容器的配置文件,该文件默认在srcpublic ApplicationContext(String iocBeanXmlFile) throws DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException {//1, 得到类加载路径String path this.getClass().getResource(/).getPath();// 创建saxreader,它用于读取 XML 文件并将其转换为 Java 对象。
// 这个类是基于 SAX (Simple API for XML) 解析器的
// 它允许你以流的方式读取 XML 文件而不需要将整个文件加载到内存中SAXReader saxReader new SAXReader();//得到document对象Document document saxReader.read(new File(path iocBeanXmlFile));//得到rootdocumentElement root document.getRootElement();//获取bean元素Element bean (Element) root.elements(bean).get(0);//获取id,属性,属性值,类的全路径String id bean.attributeValue(id);String classPath bean.attributeValue(class);ListElement 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? aclass Class.forName(classPath);//这里o对象就是monster,Monster o (Monster) aclass.newInstance();//给对象转化类型,赋值//1.反射赋值
// Method[] declaredMethods aclass.getDeclaredMethods();
// for (Method declaredMethod : declaredMethods ) {
// declaredMethod.invoke();
// }//2.直接赋值o.setMonsterid(monsterId);o.setName(name);o.setSkill(skill);//将创建的对象放入容器中singletonobject.put(id, o);}public Object getBean(String id) {//获取容器中的对象return singletonobject.get(id);}}测试类的编写
package com.applicationcontext;import com.bean.Monster;
import org.dom4j.DocumentException;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** Author: zs* Description: TODO* DateTime: 2024/9/10 12:18**/
public class ApplicationContextTest {public static void main(String[] args) throws DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException {ApplicationContext ioc new ApplicationContext(beans.xml);Monster monster01 (Monster)ioc.getBean(monster01);System.out.println(monster01);System.out.println(monster01.getClass());System.out.println(monster01.getName());System.out.println(ok);}
}Spring管理bean-IOC
bean的配置方式1.基于xml文件配置的方式
2.基于注解
bean的管理:1.创建bean对象
2.注入属性
基于xml形式
1.通过类型获取 !-- 配置monster 通过类型获取--bean classcom.bean.Monster!--1.当我们给某个bean对象设置属性时底层使用setter方法完成的--property namemonsterid value100/property namename value牛哈/property nameskill value叫//beanApplicationContext ioc new ClassPathXmlApplicationContext(beans.xml);//直接传入class类型Monster bean ioc.getBean(Monster.class);System.out.println(bean bean);}要求类型获取bean,要求容器IOC中的同一个类的bean只能有一个,否则会抛出异常NouUniqueBeanDefinitionException 应用场景:在一个线程中只需要一个对象实例的情况(单例) 2.通过构造器配置bean
!-- 配置monster对象,通过构造器--bean idmonster03 classcom.bean.Monster
!-- index索引表示构造器的第几个参数 从零开始计算--
!-- 除了index 还可以通过name / type 来指定 类的构造器,不能有完全相同类型顺序的构造器
--constructor-arg value200 index0/constructor-arg value猴 index1/constructor-arg value变 index2//beanTestpublic void setBeanByConstructor(){ApplicationContext ioc new ClassPathXmlApplicationContext(beans.xml);Monster monster03 ioc.getBean(monster03,Monster.class);System.out.println(monster03 monster03);}通过P名称空间配置
//通过p名称空间来设置属性
Test
public void setBeanByCP(){ApplicationContext ioc new ClassPathXmlApplicationContext(beans.xml);Monster monster06 ioc.getBean(monster06, Monster.class);System.out.println(monster06);
}!-- 通过P名称空间配置--
!-- 在编写代码时.p会报错,p空间没绑定--
!-- 解决方法:光标放在爆红的地方,按altint 有时需要多试几次--bean idmonster06 classcom.bean.Monsterp:monsterid500p:name红孩儿p:skill玩火/xmlns:phttp://www.springframework.org/schema/p引用其他bean
测试文件 Testpublic void setBeanByRef(){ApplicationContext ioc new ClassPathXmlApplicationContext(beans.xml);MemberServiceImpl memberService ioc.getBean(memberService, MemberServiceImpl.class);memberService.add();}
DaoImpl
public class MenberDAOImpl {//构造器.....public MenberDAOImpl() {System.out.println(MenberDAOImpl 构造器);}
// 完成添加public void add(){System.out.println(MemberDaoImpl add()方法);}
}ServiceImpl
public class MemberServiceImpl {private MenberDAOImpl menberDao;public MenberDAOImpl getMenberDao() {return menberDao;}public void setMenberDao(MenberDAOImpl menberDao) {this.menberDao menberDao;}public void add(){System.out.println(service方法被调用);menberDao.add();}
}配置文件
!-- 配置memberdaoimpl对象--bean classcom.dao.MenberDAOImpl idmemberDAO/
!-- 配置menmberserviceimpl对象--
!-- refmemdao 表示 memberserviceimpl对象的属性memberDao引用的对象是id memberDao的对象--
!-- 体现出spring容器的依赖注入--bean classcom.service.MemberServiceImpl idmemberServiceproperty namemenberDao refmemberDAO//bean引用内部bean对象
!-- 配置memberserviceimpl-使用内部bean--bean classcom.service.MemberServiceImpl idmemberService2property namememberDao bean classcom.dao.MemberDAOImpl//property/bean引用集合/数组类型的值赋值
list
!-- 配置master对象--bean classcom.bean.Master idmasterproperty namename value老头/
!-- 给list属性赋值--property namemonsterList listref beanmonster06/ref beanmonster03//list/property/bean!-- 配置master对象--bean classcom.bean.Master idmasterproperty namename value老头/
!-- 给list属性赋值--property namemonsterList list
!-- 引用的方式--ref beanmonster06/ref beanmonster03/
!-- 内部--bean classcom.bean.Monsterproperty namename value老鼠/property namemonsterid value100/property nameskill valuetoushi//bean/list/property
!-- 给map属性赋值--property namemonsterMapmapentrykeyvaluemonster03/value/keyref beanmonster03//entryentrykeyvaluemonster06/value/keyref beanmonster06//entry/map/propertyproperty namemonsterSetsetref beanmonster03/ref beanmonster06/bean classcom.bean.Monsterproperty namename value男/property namemonsterid value1000/property nameskill value吃//bean/set/property
!-- array标签中的使用value 还是bean,ref 需要根据实际情况--property namemonsterNamearrayvalue怪/valuevalue女/value/array/propertyproperty nameprospropsprop keyusernameroot/propprop keypassword123456/propprop keyip127.0.0.1/prop/props/property/bean使用util名称空间创建list
!-- 配置bookstore对象--bean classcom.bean.BookStore idbookStoreproperty namebookList refmyBookList/
!-- list--
!-- value三国演义/value--
!-- value水浒传/value--
!-- value你好/value--
!-- /list--
!-- /property--/bean
!-- 定义一个utillist 并指定一个id 可以达到复用的效果--util:list idmyBookListvalue三国演义2/valuevalue水浒传2/valuevalue你好2/value/util:listxmlns:utilhttp://www.springframework.org/schema/util级联属性赋值
在编程中级联属性赋值通常指的是在对象之间设置属性值时将一个对象的属性值赋给另一个对象的对应属性。这种操作在面向对象编程中很常见尤其是在处理具有复杂关系的对象时。级联赋值可以简化代码避免重复编写相同的赋值语句。
以Java为例假设我们有两个类 Person 和 Address其中 Person 类包含一个 Address 类型的属性
public class Address {private String street;private String city;private String zipCode;// 构造器、getter和setter省略
}public class Person {private String name;private Address address;// 构造器、getter和setter省略
}如果我们想要级联地为 Person 对象的 address 属性赋值可以这样做
public class Main {public static void main(String[] args) {Address address new Address();address.setStreet(123 Main St);address.setCity(Anytown);address.setZipCode(12345);Person person new Person();person.setName(John Doe);person.setAddress(address); // 级联赋值// 现在person对象有了一个包含地址信息的address属性}
}emp类创建
package com.bean;/*** Author: zs* Description: TODO* DateTime: 2024/9/10 17:01**/
public class Emp
{private String name;private Dept dept;public Emp() {}public String getName() {return name;}public void setName(String name) {this.name name;}public Dept getDept() {return dept;}public void setDept(Dept dept) {this.dept dept;}Overridepublic String toString() {return Emp{ name name \ , dept dept \ };}
}
dept类创建
package com.bean;/*** Author: zs* Description: TODO* DateTime: 2024/9/10 17:00**/
public class Dept {private String name;public Dept() {}public String getName() {return name;}public void setName(String name) {this.name name;}Overridepublic String toString() {return Dept{ name name \ };}
}
级联配置文件
!-- 配置dept--bean classcom.bean.Dept iddept/
!-- 配置emp--bean classcom.bean.Emp idempproperty namename valuejj/property namedept refdept/
!-- 这我希望给dept的name属性赋值--property namedept.name value开发部门//bean通过静态工厂获取对象
创建一个静态工厂类
package com.factory;import com.bean.Monster;import java.util.HashMap;
import java.util.Map;/*** Author: zs* Description: TODO* DateTime: 2024/9/10 17:22**/
public class MyStaticFactory {private static MapString, Monster monsterMap;//使用static代码块进行初始化//static代码块特点:随着类的加载而加载,并且只加载一次static {monsterMap new HashMap();monsterMap.put(monster01, new Monster(1000,你啦,跑));monsterMap.put(monster02,new Monster(100000,你,走走走));}//提供一个方法,返回monster对象public static Monster getMonster(String key) {return monsterMap.get(key);}
}
配置文件
!-- 配置一个monster对象--
!-- 通过静态工厂类获取/配置bean--
!-- class 是静态工厂的全路径--
!-- foctory-mehtod 表示是静态工厂用哪个方法返回对象--
!-- constructor-arg value 返回静态工厂的那个对象--bean idmy_monster01 classcom.factory.MyStaticFactoryfactory-methodgetMonsterconstructor-arg valuemonster02//bean不管获取多少次都是通一个对象
动态实例工厂
!-- 配置monster对象--bean idmyInstanceFactory classcom.factory.MyInstanceFactory/bean idmy_monster02 factory-beanmyInstanceFactory factory-methodgetMonsterconstructor-arg valuemonster03//bean通过factory bean
package com.factory;import com.bean.Monster;
import org.springframework.beans.factory.FactoryBean;import java.util.HashMap;
import java.util.Map;/*** Author: zs* Description: TODO* DateTime: 2024/9/11 12:55**/
public class MyFactoryBean implements FactoryBeanMonster {private String key;//就是配置时,指定获取的对象private MapString, Monster monsterMap;{monsterMap new HashMapString, Monster();monsterMap.put(monster05, new Monster(500,反复,请求));monsterMap.put(monster06, new Monster(600,ff,qq));}public void setKey(String key) {this.key key;}public Monster getObject() throws Exception {return monsterMap.get(key);}public Class? getObjectType() {return Monster.class;}public boolean isSingleton() {return true;}
}
!-- 配置factorybean--bean idmy_monster05 classcom.factory.MyFactoryBeanproperty namekey valuemonster05//beanbean的重用
bean idmonster11 classcom.hspedu.spring.beans.Monster parentmonster10/或者
使用abstract true 抽象用来继承
但是设置之后本类不能被实例化
bean创建顺序
默认是按照编写的顺序
当有依赖对象时,会先创建被依赖的对象
ioc是一个整体,先创建对象最后完成依赖关系 除depende之外
bean的单例和多实例
在spring容器中,默认按照单例创建的,即配置一个一个bean对象后,ioc容器只会创建一个bean实例
多例设置
添加标签
scope prototype设置多实例时,实例只会在执行getbean时创建
单例模式默认是lazy-init false;不是懒加载,所以容器一加载对象就会创建
bean的生命周期
bean对象的创建是由jvm完成的
1,执行构造器
2,执行set方法
3,调用bean的初始化方法
4,使用bean
5,容器关闭时,调用销毁方法
bean的后置处理器
这个对象会在bean初始化方法调用之前和调用之后调用
功能可以操作整个bean文件的对象,就像一个切面
在Spring框架中Bean后置处理器Bean Post Processor是一种特殊的组件它允许你在Spring容器初始化任何bean之后但在bean的属性被设置之后进行额外的处理。Bean后置处理器可以用来修改bean的定义、属性值或者根据特定的逻辑决定是否要返回一个代理而不是原始bean实例。
关键特点
1.实现接口Bean后置处理器需要实现 org.springframework.beans.factory.config.BeanPostProcessor 接口。 两个主要方法
postProcessBeforeInitialization(Object bean, String beanName)在bean的初始化方法如PostConstruct注解的方法或InitializingBean接口的afterPropertiesSet方法之前调用。postProcessAfterInitialization(Object bean, String beanName)在bean的初始化方法之后调用。
3.作用时机Bean后置处理器在Spring容器的bean生命周期的特定点被调用允许开发者在bean完全初始化之前和之后执行自定义逻辑。
4.返回值这两个方法都可以返回bean本身或一个代理对象。如果返回null则Spring容器会忽略该bean不再进行后续处理。
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;Component
public class CustomBeanPostProcessor implements BeanPostProcessor {Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 在bean初始化之前可以进行的操作System.out.println(Before initialization: beanName);return bean; // 返回bean本身或修改后的bean}Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {// 在bean初始化之后可以进行的操作System.out.println(After initialization: beanName);return bean; // 返回bean本身或修改后的bean}
}?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd!-- 定义你的Bean后置处理器 --bean idmyBeanPostProcessor classcom.example.MyBeanPostProcessor/!-- 定义其他bean --bean idmyService classcom.example.MyService!-- bean的配置 --/bean!-- 其他bean定义 --/bean使用场景
修改bean属性在bean初始化前后修改其属性值。条件性地返回代理根据某些条件返回一个代理对象例如用于AOP面向切面编程。资源释放在bean销毁之前执行清理工作。日志记录记录bean的创建和销毁过程。
通过过程文件给bean注入值
!-- 配置monster--context:property-placeholder locationclasspath:my.properties/bean classcom.bean.Monster idmonster10property namemonsterid value${monsterid}/property namename value${name}/property nameskill value${skill}//bean
创建一个配置文件
monsterid1000
namejack
skillheal自动装配bean
bytype-------通过类型
!-- 配置orderdao orderservice--bean classcom.dao.OederDao idoederDao/
!-- autowire bytype orderservice时通过类型的方式给对象属性自动完成赋值--
!-- 作用:在bean文件中寻找有没有orderdao类型的对象,有的化,就会自己完成装配--
!-- 注意bean文件中不能有两个orderfao的类型--bean autowirebyType classcom.service.OrderService idorderService/
!-- 手动装配--
!-- property nameoederDao refoederDao/--bean autowirebyType classcom.web.OrderAction idorderAction/创建三个文件为:dao,service,selvet
byname----通过名字完成自动装配
按照setxxx方法set后边的名字
spring EL表达式
界定符#{}
基于注解配置bean
基本使用
在Java编程中注解Annotations是一种用于为代码提供元数据的机制。注解不会直接影响代码的执行逻辑但可以被编译器、其他工具或运行时环境读取从而提供额外的信息或指导。注解在很多方面被广泛使用包括但不限于依赖注入、事务管理、日志记录、安全性检查等。
注解的基本概念
1.声明注解使用interface关键字声明一个新的注解类型。
java
public interface MyAnnotation {String value();
}2.使用注解在类、方法、变量等元素上使用注解。
java
MyAnnotation(value Example)
public class ExampleClass {// ...
}3.注解的保留策略定义注解的生命周期即它在源代码、字节码或运行时是否可用。通过Retention注解指定。
java
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;Retention(RetentionPolicy.RUNTIME)
public interface MyAnnotation {// ...
}4.注解的适用目标通过Target注解指定注解可以应用的目标类型。
java
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;Target(ElementType.METHOD)
public interface MyAnnotation {// ...
}5.注解的继承注解默认不会被子类继承但可以通过Inherited注解指定注解可以被继承。
java
import java.lang.annotation.Inherited;Inherited
public interface MyAnnotation {// ...
}常见的注解使用场景
依赖注入Spring框架使用Autowired、Qualifier等注解来实现依赖注入。
java
Autowired
private MyService myService;事务管理Transactional注解用于声明方法或类的事务边界。
java
Transactional
public void performOperation() {// ...
}RESTful Web服务JAX-RS和Spring MVC使用注解来定义资源和路由。
java
RestController
RequestMapping(/api)
public class MyController {GetMapping(/hello)public String sayHello() {return Hello, World!;}
}单元测试JUnit和TestNG使用注解来标记测试方法。
java
import org.junit.Test;
import static org.junit.Assert.*;public class ExampleTest {Testpublic void testAddition() {assertEquals(2, 1 1);}
}日志记录使用如Log或Log4j等注解来简化日志记录。
java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class MyClass {private static final Logger logger LoggerFactory.getLogger(MyClass.class);public void myMethod() {logger.info(This is an info message);}
}注解处理
编译时处理注解处理器可以在编译时生成额外的源代码、资源文件或进行其他操作。运行时处理在运行时可以通过反射API读取注解信息并根据这些信息执行特定的逻辑。
基于注解的方式配置bean主要是项目开发中的组件比如Controller、Service、和Dao。
组件注解的形式有
1.Component 表示当前注解标识的是一个组件。2.Controller 表示当前注解标识的是一个控制器通常用于Servlet。3.Service 表示当前注解标识的是一个业务逻辑的类通常用于service类。4.Repository 表示当前注解标识的是一个持久化层的类通常用于Dao类。
spring框架的注解需要引入的jar包
1.spring-aop-5.3.8.jar
仿写注解
package com.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** Author: zs* Description: TODO* DateTime: 2024/9/12 13:29**/
//规定当前自定义的的注解可以作用于那些类型
Target(ElementType.TYPE)
//指定注解的作用范围
Retention(RetentionPolicy.RUNTIME)public interface ComponentScan {//表示我们的注解可以传入一个value属性String value() default ;
}
package com.annotation;import org.springframework.stereotype.Component;/*** Author: zs* Description: TODO* DateTime: 2024/9/12 16:01**/
ComponentScan(value com.component)
public class SpringConfig {}package com.annotation;import com.applicationcontext.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;import javax.security.auth.login.Configuration;
import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;/*** Author: zs* Description: TODO* DateTime: 2024/9/13 12:46**/
public class SpringApplicationContext {//这个类的作业是模仿容器//需要拿到class类型,因为要使用反射//定义一个属性private Class configClass;//因为在框架内,bean的信息要放入容器的hashMap//所以这一要创建一个mapprivate final ConcurrentHashMapString, Object ioc new ConcurrentHashMap();//构造器,在初始化容器时,选用传入beans.xml文件//public SpringApplicationContext(Class configClass) {//配置类不止在构造器使用,跨方法使用//拿到配置类的class类型,就可以到的注解//就可以拿到注解的value里的路径信息this.configClass configClass;
// System.out.println(this.configClass);//获取要扫描的包//1.先得到配置类的注解ComponentScan componentScan (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);//通过comonentScan得到valueString path componentScan.value();//获得value下的所有class的信息//1.得到类的加载器ClassLoader classLoader ApplicationContext.class.getClassLoader();//2.通过加载器获得要扫描包的资源路径,class文件的信息不是在src而是在out//Java中解析路径识别不出. 所有要把查找出来com. 的路径转化为com/path path.replace(., /);URL resource classLoader.getResource(path);//3.将要加载的资料(.class)路径下的文件进行遍历//注意:如果要有子目录,需要进行递归File file new File(resource.getFile());if (file.isDirectory()) {File[] files file.listFiles();for (File f : files) {System.out.println(f.getAbsolutePath());String fileAbsolutePath f.getAbsolutePath();//过滤,只处理.class文件if (fileAbsolutePath.endsWith(.class)) {//获取全类名,反射对象,放入容器中//1.获取类名String className fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf(\\) 1, fileAbsolutePath.lastIndexOf(.class));//2.获取类的路径String classFullName path.replace(/, .) . className;//判断文件是不是需要注入容器中try {//这时我们得到该类的class对象//forname 可以通过反射加载类对象//loadclass 也可以//但是forname会调用该类的静态方法,Class? aClass classLoader.loadClass(classFullName);if(aClass.isAnnotationPresent(Component.class) || aClass.isAnnotationPresent(Controller.class)|| aClass.isAnnotationPresent(Service.class) ||aClass.isAnnotationPresent(Repository.class)) {//指定value 分配idif(aClass.isAnnotationPresent(Component.class)) {Component component aClass.getDeclaredAnnotation(Component.class);String id component.value();if (!.endsWith(id)) {className id;}}//这里为什么用forname 会调用静态方法,会把类的联系加载进去Class? aClazz Class.forName(classFullName);Object instance aClazz.newInstance();//类的小写首字母作为idioc.put(StringUtils.uncapitalize(className), instance);}} catch (Exception e) {e.printStackTrace();}}}}}//编写方法返回容器对象public Object getBean(String beanName) {return ioc.get(beanName);}
}注解自动装配
1.基于注解配置bean也可实现自动装配使用的注解是AutoWired 或者 Resource AutoWired 的规则说明 在IOC容器中查找待装配的组件的类型如果有唯一的bean匹配则使用该bean装配。 如待装配的类型对应的bean在IOC容器中有多个则使用待装配的属性名作为id值再进行查找找到就装配找不到就抛异常。 操作流程 ?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdcontext:component-scan base-packagecom.component//beans在IOC容器中查找待装配的组件的类型如果有唯一的bean匹配则使用该bean装配。
Controller
public class UserAction {Autowiredprivate UserService userService;public void sayOk() {System.out.println(UserAction);userService.hi();}
}
Service
public class UserService {public void hi(){System.out.println(hi);}
}
如待装配的类型对应的bean在IOC容器中有多个则使用待装配的属性名作为id值再进行查找找到就装配找不到就抛异常。
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdcontext:component-scan base-packagecom.component/bean classcom.component iduserService200/bean classcom.component iduserService300/
/beans3.Resource 的规则说明
Resource有两个属性是比较重要的分别是name和type。Spring将Resource注解的name属性解析为bean的名字而type属性解析为bean的类型。所以如果使用name属性则使用byName的自动注入策略如果使用type属性则使用byType的自动注入策略。
使用type时,对象必须是单例的]
如果Resource没有name和type则先使用byName注入策略如果匹配不上再使用byType策略如果都不成功就会报错。
建议不管是AutoWired 还是 Resource都应谨慎使用确保理解其自动装配的规则和潜在的异常情况以避免运行时错误。
Controller
public class UserAction {Resource(name userService200)private UserService userService;public void sayOk() {System.out.println(UserAction);System.out.println(useraction自动装配的 userService);userService.hi();}
}
配置文件不变
泛型依赖注入
泛型:
1.普通成员可以使用泛型属性、方法2.使用泛型的数组不能初始化3.静态方法中不能使用类的泛型4.泛型类的类型是在创建对象时确定的因为创建对象时需要指定确定类型5.如果在创建对象时没有指定类型默认为Object
aop
动态代理
动态代理是 Java 中一种非常强大的特性它允许在运行时创建一个实现了某个接口的代理对象这个代理对象可以作为目标对象的替代品。动态代理在很多场景下非常有用比如
1.日志记录在方法调用前后添加日志记录。2.事务管理在方法调用前后管理数据库事务。3.安全检查在方法调用前进行权限验证。4.缓存缓存方法的返回结果避免重复计算。5.延迟加载实现对象的延迟加载机制。6.远程方法调用在远程方法调用RMI中动态代理可以用来封装远程调用的细节。
动态代理的实现
在 Java 中动态代理主要通过 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来实现。
Proxy 类用于生成动态代理实例。InvocationHandler 接口定义了代理实例上的方法调用处理程序。
package com.aop;import java.lang.reflect.*;
import java.util.Arrays;/*** Author: zs* Description: TODO* DateTime: 2024/9/14 15:22**/
public class ProxyProvider {//创建一个目标对象,这个对象要实现接口private SmartAnimal smart_traget;public ProxyProvider(SmartAnimal smart_traget) {this.smart_traget smart_traget;}//创建一个代理对象,我们要用代理对象如执行目标对象的方法public SmartAnimal getProxy() {//1.类加载器ClassLoader classLoader smart_traget.getClass().getClassLoader();//2.目标接口信息Class?[] interfaces smart_traget.getClass().getInterfaces();//3.创建一个InvocationHandlerInvocationHandler invocationHandler new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result null;try {//横切关注点System.out.println(方法执行前 method.getName() 参数 Arrays.asList(args));//返回执行结果//使用反射方法调用方法result method.invoke(smart_traget, args);//横切接入点System.out.println(方法执行后 method.getName() 结果 result);} catch (Exception e) {e.printStackTrace();//如果执行方发时,出现异常,就会进入catchSystem.out.println(方法 method.getName() 执行异常 结果 e.getClass().getName());} finally {//最中都会执行到这里//横切关注点,最终通知System.out.println(方法 method.getName() 名);}return result;}};//创建代理对象----动态代理类型SmartAnimal proxy (SmartAnimal)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);return proxy;}}面向切面编程Aspect-Oriented ProgrammingAOP是一种编程范式旨在将横切关注点cross-cutting concerns从业务逻辑中分离出来以提高模块化。横切关注点是指那些影响多个类的问题比如日志记录、事务管理、安全性等。AOP 通过创建切面aspects来实现这一点切面可以定义在何处以及如何将额外的行为插入到程序代码中。
AOP 的关键概念
1.切面Aspect一个关注点的模块化这个关注点可能会横切多个对象。事务管理是切面的一个典型例子。2.连接点Join Point在程序执行过程中某个特定的点比如方法的调用或异常的抛出。在Spring AOP中连接点总是方法的执行点。3.通知Advice在切面的某个特定的连接点上执行的动作。不同类型的通知包括“前置通知”在方法调用之前、“后置通知”在方法成功执行之后、“异常通知”在方法抛出异常后、“最终通知”无论方法执行成功还是失败都会执行和“环绕通知”围绕方法执行的通知。4.引入Introduction允许我们向现有的类添加新的方法或属性。5.织入Weaving把切面应用到目标对象并创建新的代理对象的过程。织入可以在编译时、加载时或运行时完成。
AOP 在 Spring 中的实现
Spring AOP 是 Spring 框架的一部分它使用代理模式来实现 AOP。Spring AOP 只支持方法级别的连接点这意味着它只能在方法执行时进行拦截。
使用 Aspect 注解在 Spring 中你可以使用 Aspect 注解来定义一个切面类。定义通知使用 Before、After、AfterReturning、AfterThrowing 和 Around 等注解来定义不同类型的通知。配置 AOP在 Spring 配置中启用 AOP 支持并指定哪些类或方法应用切面。 context:component-scan base-packagecom.asp/
!-- 开启基于注解的AOP--aop:aspectj-autoproxy/切入表达式:
通过表达式的方式定位一个或多个具体的连接点
execution[[权限修饰符] [返回类型] [简单类名/全类名] [方法名] [参数列表] ]
切入表达式的注意细节
1.切入表达式也可以指向类的方法这时切入表达式会对该类/对象生效。 2.切入表达式也可以指向接口的方法这时切入表达式会对实现了接口的类/对象生效。 3.切入表达式也可以对没有实现接口的类进行切入.
动态代理机制1.jdk的proxy 面向接口 2.CGlib 是面向父类
两个动态代理的区别
1.JDK动态代理是面向接口的只能增强实现类中接口中存在的方法。CGlib是面向父类的可以增强父类的所有方法。2.JDK得到的对象是JDK代理对象实例而CGlib得到的对象是被代理对象的子类。
在类和切面类在一个包下可以简写类名
JoinPoint
public void beforeMethod(JoinPoint joinPoint){joinPoint.getSignature().getName(); // 获取目标方法名joinPoint.getSignature().getDeclaringType().getSimpleName(); // 获取目标方法所属类的简单类名joinPoint.getSignature().getDeclaringTypeName(); // 获取目标方法所属类的类名joinPoint.getSignature().getModifiers(); // 获取目标方法声明类型(public, private, protected)Object[] args joinPoint.getArgs(); // 获取传入目标方法的参数返回一个数组joinPoint.getTarget(); // 获取代理对象joinPoint.This(); // 获取代理对象自己
}Aop切面优先级
order(valuen) 来控制 n 值越小优先级越高。
运行原理类似filter
基于xml配置Aop
bean.xml文件配置
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd!-- 使用xml,完成aop编程--bean classcom.aopxml.SmartAnimalAspect idanimalAspect/
!-- 配置一个smartdog--bean classcom.aopxml.SmartDog idsmartDog/
!-- 配置切面类--aop:config
!-- 这里指定切面对象--
!-- aop:aspect refanimalAspect order10/--!--配置切入点--aop:pointcut idmyPointCut expressionexecution(public float com.aopxml.SmartDog.getSum(float,float))/
!-- 这里指定切面对象--aop:aspect refanimalAspect order10!--配置前置通知--aop:before methodshowBeginLog pointcut-refmyPointCut/!--返回通知--aop:after-returning methodshowSuccessEndLog pointcut-refmyPointCut returningres/!--异常通知--aop:after-throwing methodshowExceptionLog pointcut-refmyPointCut throwingthrowable/!--最终通知--aop:after methodshowFinallyEndLog pointcut-refmyPointCut/!-- aop:around method--/aop:aspect/aop:config
/beans