编程杂谈

新博客:https://blog.bigdataboy.cn/article/453.html什么是事务事务是逻辑上的一组操作,主要是对数据库的数据的操作,要么都执行,要么都不执行,重点是都,所以当这组操作不一致时,那么就自动进行回滚,把数据恢复到这组操作之前,这样数据库的数据就不会出错了。转账案例事务这个概念最早是在数据库接触到,但是感觉并不明显,这里可以通过这个案例感受一下a给b转账100正常情况a的余额减少100b的余额增加100publicvoidtransfer(Stringout,Stringin,Doublemoney){//转账accountDao.inMoney(in,money);accountDao.outMoney(out,money);}如果在转账过程中出现异常,不使用事务的话,就会出现,一方钱减少了,而另一方确没有增加publicvoidtransfer(Stringout,Stringin,Doublemoney){//转账accountDao.inMoney(in,money);//期间出现报错accountDao.outMoney(out,money);}Spring事务处理第一步、定义该函数需要事务处理,在接口上定义项目使用的DataSource要一样,不然事务无法实现,案例中指MyBatis初始化SqlSessionFactoryBean时传入的DataSource和JDBC交给Spring的事务的DataSource一致publicinterfaceAccountService{@Transactional//该注解开启事务publicvoidtransfer(Stringout,Stringin,Doublemoney);}第二步、在JdbcConfig类,定义事务管理Bean交给Spring容器管理@ConfigurationpublicclassJdbcConfig{@Value("${jdbc.driver}")publicStringdriverClassName;@Value("${jdbc.url}")publicStringurl;@Value("${jdbc.username}")publicStringusername;@Value("${jdbc.password}")publicStringpassword;@BeanpublicDataSourcedataSource(){DruidDataSourcedataSource=newDruidDataSource();dataSource.setDriverClassName(driverClassName);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);returndataSource;}@Bean//把事务管理器交给Spring管理publicDataSourceTransactionManagerdataSourceTransactionManager(DataSourcedataSource){DataSourceTransactionManagertransactionManager=newDataSourceTransactionManager();transactionManager.setDataSource(dataSource);returntransactionManager;}}第三步、在SpringConfig使用注解开启事务@Configuration@ComponentScan({"cn.bigdataboy"})@PropertySource({"classpath:jdbc.properties"})@Import({MyBatisConfig.class,JdbcConfig.class})@EnableTransactionManagement//开启事务管理器publicclassSpringConfig{}测试注意默认状态下并不是所有的异常都会回滚,可以通过事务属性进行控制事务角色在上述案例中,小事务一和二(事务协调员)会被加入到大的事务(事务管理员),由事务管理员统一管理事务管理员:在Spring中通常指开启事务的方法事务协调员:在Spring中通常指数据层方法,也可以是业务层方法事务的属性事务的属性能使事务管理员对事务协调员精细化的管理属性作用实例readOnly设置是否为只读事务readOnly=true只读事务timeout设置事务超时时间timeout=-1(永不超时)rollbackFor设置事务回滚异常(class)rollbackFor={NullPointerException.class}rollbackForClassName设置事务回滚异常(String)同上,只是参数为字符串noRollbackFor设置事务不回滚异常(class)noRollbackFor={NullPointerException.class}noRollbackForClassName设置事务不回滚异常(String)同上,只是参数为字符串propagation事务传播见下面事务传播默认情况下,发送错误时,子事务全部都要回滚,那有一些事务是不需要回滚(记录日志到数据库),这也是需要实现的,子事务可以控制自己是否需要主事务控制。publicinterfaceAccountLogService{@Transactional(propagation=Propagation.REQUIRES_NEW)//该注解开启事务publicvoidadd(Stringout,Stringin,Doublemoney);}propagation参数说明(T代表事务)传播属性事务管理员事务协调员REQUIRED(默认)开启T/无加入T/新建T2REQUIRES_NEW开启T/无新建T2/新建T2SUPPORTS开启T/无加入T/无NOT_SUPPORTED开启T/无无/无MANDATORY开启T/无加入T/ERRORNEVER开启T/无ERROT/无NESTED开启T/无设置savePoint,一但事务回滚,事务将回滚到savaPoint处,交由客户端提交/回滚案例代码:https://pan.bigdataboy.cn/s/QgVFn

编程杂谈

新博客:https://blog.bigdataboy.cn/article/451.html说明学校的小组课程,自行拟定项目,我们小组做的是客户端控制风扇、警报、大门、灯泡,打开摄像头并识别其中的车牌号,还实现了温度异常监控,自动开关灯,因为没有板子,用仿真软件模拟的控制设备。实现效果采用技术我是使用Python实现上述功能服务端:FastAPI、apscheduler客户端:PyQt5通信方式客户端---post--->服务端(单向)客户端<---WebSocket--->服务端(双向)服务端<--串口-->仿真平台架构图服务端启动事件在FastAPI的事件里,连接串口,启动后台监控任务@app.on_event("startup")asyncdefstartup_event():start_serial("COM41",115200)logger.info("串口连接成功")scheduler.add_job(MonitorService().run,trigger="interval",seconds=1,max_instances=10)scheduler.start()logger.info("后台监控任务启动成功")后台监控任务后台监控任务启动时,FastAPI没有启动完成,所以这时后台监控任务的WebSocket是不能及时连接上,所以需要做判断,没有连上或者断开了就连接self.ws:WebSocket=websocket.WebSocket()...try:#测试是否连通self.ws.recv()#骚操作第一次测试连接,后面防止断开exceptWebSocketConnectionClosedException:#尝试连接try:self.ws.connect(f"ws://127.0.0.1:8080/ws/data?user=monitor")exceptWebSocketExceptionase:logger.error(f"连接失败:{e}")exceptConnectionRefusedErrorase:logger.error(f"连接失败:{e}")else:logger.success("监控任务连接成功")exceptConnectionAbortedErrorase:try:self.ws.connect(f"ws://127.0.0.1:8080/ws/data?user=monitor")exceptWebSocketExceptionase:logger.error(f"连接失败:{e}")exceptConnectionRefusedErrorase:logger.error(f"连接失败:{e}")else:logger.success("重新连接成功")群发仿真平台环境数据后台监控任务连接上WebSocket,就会把环境信息发给WebSocket接口就会群发到其他连接的客户端上。群发的实现就是把连接后的WebSocket对象保存起来,然后循环发送。classConnectionManager:def__init__(self):#存放需要广播的的链接self.active_connections:List[Dict[str,WebSocket]]=[]asyncdefconnect(self,user:str,ws:WebSocket):#链接awaitws.accept()self.active_connections.append({"user":user,"ws":ws})defdisconnect(self,user:str,ws:WebSocket):#关闭时移除ws对象self.active_connections.remove({"user":user,"ws":ws})asyncdefbroadcast_json(self,data:dict):#广播消息forconnectioninself.active_connections:awaitconnection['ws'].send_json(data)manager=ConnectionManager()@ws_app.websocket("/data")asyncdefwebsocket_endpoint(websocket:WebSocket,user:str):awaitmanager.connect(user,websocket)try:whileTrue:data=awaitwebsocket.receive_json()#等待请求,才响应#logger.debug(data)ifdata.get("user")=="monitor":data.get("data")["park_all"]=ParkingService.get_all()#全部车位data.get("data")["park_remain_num"]=ParkingService.get_remain_num()#剩余车位awaitmanager.broadcast_json(data["data"])#是监控服务发来的直接广播消息exceptConnectionClosedError:logger.error(f"{user}ConnectionClosedError")manager.disconnect(user,websocket)exceptWebSocketDisconnect:logger.error(f"{user}WebSocketDisconnect")manager.disconnect(user,websocket)客户端为了防止界面“假死”,耗时操作使用线程完成,这里的WebSocket连接更新环境数据,摄像头的使用,识别车牌均使用了线程PyQt使用摄像摄像头使用的cv2库,界面显示的画面,其实一帧一帧的显示的显示到Label组件上的,所以子线程也是把画面一帧一帧的发送出来。classCameraThread(QThread):frame_signal=pyqtSignal(numpy.ndarray)#获取的换面其实一种矩阵is_open_signal=pyqtSignal(bool)close_video_signal=pyqtSignal(bool)def__init__(self,parent=None):super().__init__(parent)self.is_open_video=True#defrun(self)->None:capture=cv2.VideoCapture(0)whileself.is_open_video:#读取摄像头显示视频ifcapture.isOpened():ret,frame=capture.read()#读取画面frame=cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)self.frame_signal.emit(frame)#把图片发射出去else:self.is_open_signal.emit(capture.isOpened())#打开摄像头失败ifnotself.is_open_video:#摄像头关闭清理资源发送信号capture.release()self.close_video_signal.emit(True)#打开摄像头失败WebSocket连接classWSThread(QThread):info_signal=pyqtSignal(dict)ws:WebSocket=Nonedef__init__(self,parent=None):super().__init__(parent)defrun(self)->None:print("WSThreadrunning")whileTrue:date=json.loads(self.ws.recv())print(date)#发送信号self.info_signal.emit(date)time.sleep(0.2)全部代码:https://pan.bigdataboy.cn/s/dm9tk

编程杂谈

新博客:https://blog.bigdataboy.cn/article/450.htmlMyBatis说明mybatis-spring官网:https://mybatis.org/spring/zh/index.html介绍:MyBatis-Spring会帮助你将MyBatis代码无缝地整合到Spring中。它将允许MyBatis参与到Spring的事务管理之中,创建映射器mapper和SqlSession并注入到bean中,以及将Mybatis的异常转换为Spring的DataAccessException。添加Jar依赖pom.xml文件添加,注意版本问题<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.10.RELEASE</version></dependency><!--springjdbc操作--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.2</version></dependency><!--阿里巴巴数据源--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.24</version></dependency><!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><!--mybatisspring结合--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.7</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.8</version></dependency></dependencies>添加配置类和配置文件数据库Sql文件SETNAMESutf8mb4;SETFOREIGN_KEY_CHECKS=0;--------------------------------Tablestructureforaccount------------------------------DROPTABLEIFEXISTS`account`;CREATETABLE`account`(`id`int(11)NOTNULLAUTO_INCREMENT,`users`varchar(255)CHARACTERSETutf8mb4COLLATEutf8mb4_binNULLDEFAULTNULL,`money`double(255,0)NULLDEFAULTNULL,PRIMARYKEY(`id`)USINGBTREE)ENGINE=InnoDBAUTO_INCREMENT=3CHARACTERSET=utf8mb4COLLATE=utf8mb4_binROW_FORMAT=Compact;--------------------------------Recordsofaccount------------------------------INSERTINTO`account`VALUES(1,'a',100);INSERTINTO`account`VALUES(2,'b',200);SETFOREIGN_KEY_CHECKS=1;jdbc.properties在resources文件夹下jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://127.0.0.1:3306/spring_dbjdbc.username=rootjdbc.password=rootJdbcConfig配置类Spring第三方Bean管理@ConfigurationpublicclassJdbcConfig{@Value("${jdbc.driver}")publicStringdriverClassName;@Value("${jdbc.url}")publicStringurl;@Value("${jdbc.username}")publicStringusername;@Value("${jdbc.password}")publicStringpassword;@BeanpublicDataSourcedataSource(){DruidDataSourcedataSource=newDruidDataSource();dataSource.setDriverClassName(driverClassName);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);returndataSource;}}MyBatisConfig配置类Spring第三方Bean管理@ConfigurationpublicclassMyBatisConfig{@Bean//连接工厂BeanpublicSqlSessionFactoryBeansqlSessionFactory(DataSourcedataSource)throwsException{SqlSessionFactoryBeanfactoryBean=newSqlSessionFactoryBean();factoryBean.setDataSource(dataSource);returnfactoryBean;}@Bean//MapperBeanpublicMapperScannerConfigurermapperScannerConfigurer(){MapperScannerConfigurermapperScannerConfigurer=newMapperScannerConfigurer();mapperScannerConfigurer.setBasePackage("cn.bigdataboy.dao");//设置Mapper映射的包,扫描Mapper注解,已经转化成Mapper,相对于以前的Mapper配置returnmapperScannerConfigurer;}}Spring配置类@Configuration@ComponentScan({"cn.bigdataboy"})@PropertySource({"classpath:jdbc.properties"})@Import({MyBatisConfig.class,JdbcConfig.class})//导入配置publicclassSpringConfig{}添加实体类实体类,就是查询结果的映射类,在domain文件夹下publicclassAccount{privateintid;privateStringusers;privateDoublemoney;@OverridepublicStringtoString(){return"Account{"+"id="+id+",users='"+users+'\''+",money="+money+'}';}}添加dao层dao层是数据处理,结合Mybatis后,就是原来的Mapper配置@MapperpublicinterfaceAccountDao{@Select("SELECT*FROMaccountWHEREid=#{userId}")AccountgetUserById(@Param("userId")intuserId);@Select("SELECT*FROMaccount")List<Account>getAllUser();}添加service层业务处理层,实现两个功能,按id查询和查询全部@ServicepublicclassAccountServiceImplimplementsAccountService{@AutowiredprivateAccountDaoaccountDao;@OverridepublicAccountgetUserById(intid){returnaccountDao.getUserById(id);}@OverridepublicList<Account>getAllUser(){returnaccountDao.getAllUser();}}测试publicclassApp{publicstaticvoidmain(String[]args){AnnotationConfigApplicationContextcontext=newAnnotationConfigApplicationContext(SpringConfig.class);AccountServiceaccountService=context.getBean(AccountService.class);Accountaccount=accountService.getUserById(1);System.out.println(account);System.out.println(accountService.getAllUser());}}案例代码:https://pan.bigdataboy.cn/s/mXnux

编程杂谈

新博客:https://blog.bigdataboy.cn/article/449.html概念AOP(面向切面编程)是一种编程思想,Python的装饰器有这种思想,逆向中的Hook技术也有这种思想在不改变原来方法的情况下,增加功能,只是在不同框架,不同语言下,实现方式和写法不一样实现思路:获取原来函数-执行顺序-参数&返回值增强方法,那肯定会让原来的方法肯执行,所以得需要获取原来方法既然还要增强方法,那得考虑增强的逻辑什么时候执行吧,是在原来的函数执行前,还是执行后吧最后是参数和返回值的问题,既然是增强,那我的参数和返回值要符合原来的函数的规则Spring的实现方式在pom.xml添加依赖<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><!--用来解析切入点表达式--><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency></dependencies>编写增强方法类,这个类还是需要按照Spring的规则变成交给容器管理的Bean@Component//记得BeanpublicclassAdvice{}获取原来的方法,Spring使用了一种用表达式匹配的方式,后面详细介绍@Component//记得BeanpublicclassAdvice{@Pointcut("execution(voidcn.bigdataboy.dao.NameDao.getById())")//切入点表达式privatevoidpt(){}//可以理解为代表原方法}编写增强逻辑的方法,并设定执行的时机,有五种,后面详细介绍@Component//记得BeanpublicclassAdvice{@Pointcut("execution(voidcn.bigdataboy.dao.NameDao.getById())")privatevoidpt(){}//可以理解为代表原方法@Before("pt()")//增强方法执行时机,有五种publicvoidmethod(){//增强的方法在这里System.out.println("当前执行时间:"+System.currentTimeMillis());}}添加注解,告诉Spring这是AOP的类@Component//记得Bean@Aspect//添加注解publicclassAdvice{@Pointcut("execution(voidcn.bigdataboy.dao.NameDao.getById())")privatevoidpt(){}//可以理解为代表原方法@Before("pt()")//增强方法执行时机,有五种,参数是原方法publicvoidmethod(){//增强的方法在这里System.out.println("当前执行时间:"+System.currentTimeMillis());}}最后在配置类添加注解,开启AOP功能@Configuration@ComponentScan({"cn.bigdataboy.dao","cn.bigdataboy.aop"})//注意Bean不要漏了@EnableAspectJAutoProxy//开启aop代理publicclassSpringConfig{}五种执行时机@Before("")在原函数执行前执行@Before("pt()")//之前执行publicvoidmethodBefore(){//增强的方法在这里System.out.println("@Beforerunning...");}@After("")在原函数执行后执行,如果原函数报错也会执行@After("pt()")//之后执行,如果原方法报错,也会执行publicvoidmethodAfter(){//增强的方法在这里System.out.println("@Afterrunning...");}@Around("")重点常用环绕执行,所以它有点特殊,有一个参数,包含原方法和它的各种信息,相对于执行锚点,能控制在增强函数的什么位置执行@Around("pt()")//环绕执行publicvoidmethodAround(ProceedingJoinPointpjp)throwsThrowable{//增强的方法在这里System.out.println("当前执行时间@Around:"+System.currentTimeMillis());pjp.proceed();//相对于传入锚点,执行位置System.out.println("当前执行时间@Around:"+System.currentTimeMillis());}@AfterReturning("")原方法成功执行时触发,原方法报错,则不会执行@AfterReturning("pt()")//在原方法正常执行后才会触发,也就说入原方法报错,就不会触发了publicvoidmethodAfterReturning(){//增强的方法在这里System.out.println("@AfterReturningrunning...");}@AfterThrowing("")在原方法报错触发@AfterThrowing("pt()")//在原方法报错触发publicvoidmethodAfterThrowing(){//增强的方法在这里System.out.println("@AfterThrowingrunning...");}切入点表达式切入点表达式,是Spring用来表达增强方法对哪些方法生效的式子@Pointcut("execution(voidcn.bigdataboy.dao.NameDao.getById())")privatevoidpt(){}//可以理解为代表原方法格式:动作关键字(访问修饰符返回值类型包名.类/接口名.方法名(参数)异常名)(有些是可以省略的)动作关键字:几乎都是execution()访问修饰符:public、private...可以省略返回值:是什么写什么异常名:方法中定义的抛出异常,可以省略切入点表达式通配快速描述*:单个独立的任意符号,可以独立出现,可以作为前缀或者后缀的匹配符出现execution(*cn.bigdataboy.dao.*Dao.getBy*())..:多个连续的任意符号,可以独立出现,常用于简化包名和参数出现execution(*cn..NameDao.getById(..))+:专用于匹配子类型execution(*cn.bigdataboy.dao.NameDao+.*())参数&返回值处理既然是增强方法,那参数和返回值就要处理,那同时,如果方法异常,那异常信息也要处理。都是使用形参获取的。参数处理@Before、@After、@AfterReturning、@AfterThrowing都是传入JoinPoint对象执行getArgs()获取原始方法参数数组JoinPoint对象包含大量信息对于@Around是传入ProceedingJoinPoint对象执行getArgs()获取原始方法参数数组返回值处理对于返回值,只有@Around、@AfterReturning有,其他的不涉及返回值@Around方式设计参数和返回值,所以为了规范,返回值可以是Object@Around("pt()")//环绕执行publicObjectmethodAround(ProceedingJoinPointpjp)throwsThrowable{//增强的方法在这里System.out.println("@Aroundrunningargs:"+Arrays.toString(pjp.getArgs()));Objectproceed=pjp.proceed(pjp.getArgs());//相对于锚点,执行位置System.out.println("@Aroundrunningres:"+proceed);returnproceed;}@AfterReturning获取返回值有点特殊,需要指定注解的returning参数@AfterReturning(value="pt()",returning="ret")//在原方法正常执行后才会触发,也就说入原方法报错,就不会触发了publicvoidmethodAfterReturning(Objectret){//增强的方法在这里System.out.println("@AfterReturningrunningres:"+ret);}案例代码:https://pan.bigdataboy.cn/s/Lglh5

编程杂谈

新博客:https://blog.bigdataboy.cn/article/448.html管理第三方Bean第三方Bean没有办法写给它注解,所以就只能添加,Spring的处理是在配置类中写一个函数,该函数使用@Beam注解第三方Bean配置类第三方Bean的配置类,建议单独文件编写,这样不冗余,全部写一个配置类,会变得一大坨importcom.alibaba.druid.pool.DruidDataSource;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjavax.sql.DataSource;@ConfigurationpublicclassJdbcConfig{@Bean//表示返回一个Bean,也可以指定id->@Bean("dataSource")publicDataSourcedataSource(){//参数先空着DruidDataSourcedataSource=newDruidDataSource();dataSource.setDriverClassName("");dataSource.setUrl("");dataSource.setUsername("");dataSource.setPassword("");returndataSource;}}在主配置类导入第三方配置类@Configuration@ComponentScan({"cn.bigdataboy.dao"})@Import({JdbcConfig.class})//导入publicclassSpringConfig{}获取第三方Bean第三方Bean的注入资源上面的例子,JDBC的链接还空着,所以我们需要为其注入参数注入简单类型注入方式与注入自己的Bean一样,使用成员属性添加@Value()注解importcn.bigdataboy.dao.NameDao;importcom.alibaba.druid.pool.DruidDataSource;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjavax.sql.DataSource;@ConfigurationpublicclassJdbcConfig{@Value("${jdbc.driver}")publicStringdriverClassName;@Value("${jdbc.url}")publicStringurl;@Value("${jdbc.username}")publicStringusername;@Value("${jdbc.password}")publicStringpassword;@Bean//表示返回一个Bean,也可以指定id->@Bean("dataSource")publicDataSourcedataSource(){System.out.println(this.driverClassName);System.out.println(this.url);DruidDataSourcedataSource=newDruidDataSource();dataSource.setDriverClassName(this.driverClassName);dataSource.setUrl(this.url);dataSource.setUsername(this.username);dataSource.setPassword(this.password);returndataSource;}}注入引入类型这里注入引入类型,有点不一样,直接添加成方法参数就好,因为Spring容器中已经存在相应的Bean,那么它也就能自己找到,因此也容易想到它是使用类型方式找的importcn.bigdataboy.dao.NameDao;importcom.alibaba.druid.pool.DruidDataSource;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjavax.sql.DataSource;@ConfigurationpublicclassJdbcConfig{@Bean//表示返回一个Bean,也可以指定id->@Bean("dataSource")publicDataSourcedataSource(NameDaonameDao){//添加成参数System.out.println(nameDao);//打印一下,表示注入成功DruidDataSourcedataSource=newDruidDataSource();//相应配置returndataSource;}}案例代码:https://pan.bigdataboy.cn/s/NO5sp

编程杂谈

新博客:https://blog.bigdataboy.cn/article/444.html注解开发配置文件的作用降低,只需要完成扫描器的定义就行,类上添加一个注解,就表示该类是容器管理的Bean类添加注解importcn.bigdataboy.service.NameService;importorg.springframework.stereotype.Component;@Component("nameService")//参数就是idpublicclassNameServiceImplimplementsNameService{publicvoidsave(){System.out.println("servicesave...");}}类注解的官方推荐使用importorg.springframework.stereotype.Controller;importorg.springframework.stereotype.Repository;importorg.springframework.stereotype.Service;importorg.springframework.stereotype.Component;@Controller//表现层@Service//业务层@Repository//数据层@Component("nameService")//其他层配置添加扫描器<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--定义扫描器上面的命名空间要完整,idea自动的生成的不完整--><context:component-scanbase-package="cn.bigdataboy"/></beans>纯注解开发不再需要配置文件,所以也很容易想到,配置文件转变成配置类,同时也就能想到,在初始化容器时,传入的也就不是配置文件,而是配置类了配置类格式importorg.springframework.context.annotation.ComponentScan;importorg.springframework.context.annotation.Configuration;@Configuration//表示配置类@ComponentScan({"cn.bigdataboy.dao","cn.bigdataboy.service"})//扫描器定义多个路径,可以通配,建议准确一点,毕竟有些类不建议Bean化publicclassSpringConfig{}使用importcn.bigdataboy.config.SpringConfig;importcn.bigdataboy.dao.NameDao;importcn.bigdataboy.service.NameService;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;publicclassAppForAnnotation{publicstaticvoidmain(String[]args){//加载配置类AnnotationConfigApplicationContextcontext=newAnnotationConfigApplicationContext(SpringConfig.class);//从容器获取对象NameServicenameService=(NameService)context.getBean("nameService");NameDaonameDao=context.getBean("nameDao",NameDao.class);System.out.println(nameService);System.out.println(nameDao);}}案例代码:https://pan.bigdataboy.cn/s/y4jie

编程杂谈

新博客:https://blog.bigdataboy.cn/article/443.htmlsetter注入setter注入方式,就是Spring利用对象的set方法,结合书写配置的规则进行注入对象的格式添加set方法publicclassNameServiceImplimplementsNameService{privateNameDaonameDao;publicStringname;//简单类型注入publicvoidsetName(Stringname){this.name=name;}//引用类型注入publicvoidsetNameDao(NameDaonameDao){this.nameDao=nameDao;}publicvoidsave(){System.out.println(this.name+"servicesave...");nameDao.getName();}}配置文件<!--管理对象--><beanid="nameDao"class="cn.bigdataboy.dao.impl.NameDaoImpl"/><beanid="nameService"class="cn.bigdataboy.service.impl.NameServiceImpl"><!--引用类型写法--><propertyname="nameDao"ref="nameDao"/><!--简单类型写法--><propertyname="name"value="bigdataboy"/></bean>例子代码:https://pan.bigdataboy.cn/s/n8RFW构造器注入构造器的输入,不外乎需要注意参数是怎么注入的对象格式publicclassNameServiceImplimplementsNameService{publicNameDaonameDao;publicStringname;//常规写法publicNameServiceImpl(NameDaonameDao,Stringname){this.nameDao=nameDao;this.name=name;}publicvoidsave(){System.out.println(this.name+"servicesave...");nameDao.getName();}}配置文件构造器的注入,因为解耦,所以有几种写法<!--管理对象--><beanid="nameDao"class="cn.bigdataboy.dao.impl.NameDaoImpl"/><beanid="nameService"class="cn.bigdataboy.service.impl.NameServiceImpl"><!--这里的name是参数名称,这样还是耦合,所以还有其他写法--><constructor-argname="nameDao"ref="nameDao"/><constructor-argname="name"value="bigdataboy"/><!--通过类型匹配--><!--<constructor-argtype="cn.bigdataboy.dao.NameDao"ref="nameDao"/>--><!--<constructor-argtype="java.lang.String"value="bigdataboy"/>--><!--通过索引(参数位置)--><!--<constructor-argindex="0"ref="nameDao"/>--><!--<constructor-argindex="1"value="bigdataboy"/>--></bean>例子代码:https://pan.bigdataboy.cn/s/XmVTK依赖自动装配要实现自动,那肯定是需要写法规范,不然框架也不知道你要怎么装自动装配是利用set方法实现的。自动装配只能对引用类型进行装配,不能对简单类型进行装配。自动和手动配置能搭配使用,自动装配的优先级小于手动。五种自动装配模式byName对象里的set方法的名字,需要与配置文件的Beanid相对应,不然会找不到。byType这个模式就不需要id和set对应了例子代码:https://pan.bigdataboy.cn/s/254HZ集合类型注入集合类型的注入只是在配置文件的写法有区别,会有多个原素对象的格式publicclassNameServiceImplimplementsNameService{privateint[]array;privateList<String>list;privateSet<String>set;privateMap<String,String>map;privatePropertiesproperties;publicvoidsetArray(int[]array){this.array=array;}publicvoidsetList(List<String>list){this.list=list;}publicvoidsetSet(Set<String>set){this.set=set;}publicvoidsetMap(Map<String,String>map){this.map=map;}publicvoidsetProperties(Propertiesproperties){this.properties=properties;}@Overridepublicvoidsave(){System.out.println("array:"+Arrays.toString(this.array));System.out.println("list:"+this.list);System.out.println("set:"+this.set);System.out.println("map:"+this.map);System.out.println("properties:"+this.properties);}}配置文件格式还是简单<beanid="nameService"class="cn.bigdataboy.service.impl.NameServiceImpl"><propertyname="array"><array><value>100</value><value>200</value></array></property><propertyname="list"><list><value>100</value><value>200</value></list></property><propertyname="set"><set><value>100</value><value>200</value></set></property><propertyname="map"><map><entrykey="name"value="bigdataboy"></entry></map></property><propertyname="properties"><props><!--这个有点特殊--><propkey="name">bigdataboy</prop></props></property></bean>例子代码:https://pan.bigdataboy.cn/s/Y4jSb

编程杂谈

新博客:https://blog.bigdataboy.cn/article/442.htmlBean基础配置格式<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--管理对象--><beanid="nameDao"name="daodao2,dao3"class="cn.bigdataboy.dao.impl.NameDaoImpl"/></beans>属性列表属性描述idBean唯一标识nameBean的别名,多个由逗号、分号隔开class该Bean的类路径scope作用范围,用于规定获取的Bean是否是单例的(默认是singleton单例)scope属性singleton单例:也就是使用的是同一个对象prototype非单例:常用于对象内部是有属性保存状态的,该对象运行一次,内部的属性需要给下次的执行。Bean实例化使用构造方法实例化Bean的实例化,也是从构造方法开始,容器内部是使用反射机制完成的<beanid="nameDao"class="cn.bigdataboy.dao.impl.NameDaoImpl"scope="singleton"/>这里有个小问题,如果是非单例模式,会输出两次构造函数的打印使用工厂函数实例化需要继承FactoryBean,重写getObjectgetObjectType,isSingleton需要再写packagecn.bigdataboy.factory;importcn.bigdataboy.dao.NameDao;importcn.bigdataboy.dao.impl.NameDaoImpl;importorg.springframework.beans.factory.FactoryBean;publicclassNameDaoFactoryBeanimplementsFactoryBean<NameDao>{@OverridepublicNameDaogetObject()throwsException{returnnewNameDaoImpl();}@OverridepublicClass<?>getObjectType(){returnNameDaoImpl.class;}@OverridepublicbooleanisSingleton(){returntrue;}}配置文件只需要这样写<!--使用FactoryBean方式实例化Bean--><beanid="nameDao"class="cn.bigdataboy.factory.NameDaoFactoryBean"></bean>Bean生命周期生命周期其实很好理解,就是创建,销毁这样一个过程,既然有这样一个概念,那就可以控制相应阶段做不同的事。Spring的实现方式还是使用配置属性,指定相应方法初始化方法和销毁方法importcn.bigdataboy.dao.NameDao;importcn.bigdataboy.service.impl.NameServiceImpl;publicclassNameDaoImplimplementsNameDao{publicNameDaoImpl(){System.out.println("NameDaoImplconstructorrunning...");}publicvoidgetName(){System.out.println("getName:bigdataboy");}publicvoidinit(){//初始化方法System.out.println("namedaoinit...");}publicvoiddestory(){//销毁方法System.out.println("namedaodestory...");}}配置文件,指定相应方法<beanid="nameDao"class="cn.bigdataboy.dao.impl.NameDaoImpl"init-method="init"destroy-method="destory"/>销毁方法,需要修改成ClassPathXmlApplicationContext接口才有,不然是不会调用销毁的。