Upload
sasha-soleev
View
180
Download
0
Embed Size (px)
Citation preview
www.luxoft.com
КонфигурированиеSpring-приложений
Дворжецкий Юрий
25 июня 2016
www.luxoft.com 2
О чём доклад?
XML-based конфигурация: Почему так плохо получается? Что делать?
Annotation-based: Почему так плохо получается? Что делать?
Java-based конфигурация: Почему так плохо получается? Что делать?
Конфигурировние вместе со Spring Boot.
Properties – куда их класть и откуда брать?
Немного Spring Cloud.
www.luxoft.com 3
Конфигурации Spring-приложений
XML-based
<bean id="..."> ...</bean><mvc:view-.../>
Annotations
@Serviceclass MyService
@Autowired
Java-based
@BeanMyService my() { return new My...}
XML + Annotations
<bean .../>
@Autowired
Annotations + Java
@Autowired
@Bean MyService..
www.luxoft.com 4
XML-based конфигурация (+)
Всем знакома. Большая часть
документации и примеров с XML.
Централизованная конфигурация.
Естественно уменьшает связАнность Java-кода.
www.luxoft.com 5
XML-based конфигурация (–)
Огромные XML. XML. Необходимость изменять
в нескольких местах. Тяжело рефакторить. Не всегда работают Smart
* Ошибки в run-time.
www.luxoft.com 6
Почему так получается? Что делать?
Огромные XML: <import /> – позволяет из
одной большой XML сделать несколько маленьких.
Делить приложение на модули.
<import resource= "classpath*:context.xml"/>
www.luxoft.com 7
Почему так получается? Что делать?
Огромные XML - используйте расширения: util mvc tx security context
<util:properties location="my.properties"/>
www.luxoft.com 8
Почему так получается? Что делать?
Огромные XML - используйте Spring Expression Language: для выражений,
касающихся конфигурации; не для бизнес-логики.
<bean id="bean1"></bean><bean> <property ref="bean1"/></bean>
<!-- SpEL -->
<property value="#{new My()}"/>
www.luxoft.com 9
Почему так получается? Что делать?
Огромные XML? Много связей? Хочется auto-wiring?
<bean id="bean1"> ...</bean>
<bean autowire="byType"></bean>
www.luxoft.com 10
Почему так получается? Что делать?
Ошибки в run-time (run-time бывает разный) Используйте, по возможности,
<constructor-arg> вместо <property>. Поднимается ли контекст || часть контекста, можно
протестироватьв Unit-тестах.
www.luxoft.com 11
XML
Жизнь с XML Жизнь без XML
www.luxoft.com 12
Annotation-based конфигурация
public class MovieRecommender { @Autowired MovieCatalog movieCatalog;
// отсутствующий конструктор // отсутствующие сеттеры // ...}
@Servicepublic MovieCatalog { // ...}
Активно используется @Autowired
Стереотипы: @Controller / @RestController @Service, ...
@Value("${my.property}")
www.luxoft.com 13
Annotation-based конфигурация (+)
public class MovieRecommender { @Autowired MovieCatalog movieCatalog;
// отсутствующий конструктор // отсутствующие сеттеры // ...}
@Servicepublic MovieCatalog { // ...}
Никакого XML (или почти). Изменения в одном месте. Меньше Java-кода. Рефакторинг стал проще. Некоторые run-time ошибки
просто исчезли. spring-mvc, spring-* так и
используют.
www.luxoft.com 14
Annotation-based конфигурация (–)
Иногда нужно несколько бинов одного класса.
С @Autowired полями тяжелее пишутся Unit-тесты.
Добавить зависимость – элементарно.
public class MovieRecommender { @Autowired MovieCatalog movieCatalog;
// отсутствующий конструктор // отсутствующие сеттеры // ...}
@Servicepublic MovieCatalog { // ...}
www.luxoft.com 15
Annotation-based конфигурация
Ожидание@Serviceclass SmallService { @Autowired MyAwesomeDao dao;
public void update() { dao.updateAll(); }}
Реальностьpubli c class ApprovedSiteAPI {
publ ic stati c final Stri ng URL = RootController.API_URL + "/approved";
@Autowired private ApprovedSi teService approvedSiteServi ce; @Autowired private OAuth2TokenEntityServi ce tokenServices; @Autowired private OAuth2TokenEntityServi ce tokenServices; @Autowired private Cl ientDetai lsEntityService cli entService; @Autowired private IntrospectionResultAssembler i ntrospecti onResul tAssembler; @Autowired private UserInfoServi ce userInfoServi ce; @Autowired private ResourceSetServi ce resourceSetServi ce;
/** * Delete an approved site * */ @RequestMapping(value="/{id}", method = RequestMethod.DELETE) publ ic String deleteApprovedSite(@PathVariable(" id") Long id, ModelMap m, Principal p) { ApprovedSite approvedSite = approvedSiteServi ce.getById(id);
if (approvedSite == null) { l ogger.error("deleteApprovedSi te fai led; no approved site found for id: " + id); m .put(HttpCodeView.CODE, HttpStatus.NOT_FOUND); m .put(J sonErrorView.ERROR_MESSAGE, "Could not delete approved site. The requested approved site with id: " + id + " could not be found."); return J sonErrorView.VIEWNAME; } el se i f (!approvedSite.getUserId().equal s(p.getNam e())) { l ogger.error("deleteApprovedSi te fai led; principal " + p.getName() + " does not own approved si te" + i d); m .put(HttpCodeView.CODE, HttpStatus.FORBIDDEN); m .put(J sonErrorView.ERROR_MESSAGE, "You do not have permission to delete this approved si te. The approved site decision wi ll not be deleted."); return J sonErrorView.VIEWNAME; } el se { m .put(HttpCodeView.CODE, HttpStatus.O K); approvedSi teServi ce.remove(approvedSite); }
return HttpCodeView.VIEWNAME; }
@O ver ridepub lic OA uth 2A cce ssToke nE ntit y c rea teA cce ss Tok en (OAu th2 Au the ntic at ion aut hen tic atio n) thro ws Au the ntic at ionE xc ept ion , In va lidC lien tEx ce ptio n { if (au the nti ca tion != nu ll & & a uth ent ica tion .ge tOA ut h2R equ es t() ! = n ul l) { // l ook up o ur c lien t OA uth 2Re qu es t c li ent Aut h = a uthe nti cat ion .ge tOA uth 2Re qu es t ();
Cli ent Det ail sEn tity c li ent = cli entD eta ils Ser vic e.l oad Clie ntB yC lien tId (c li ent Aut h.g etC lie ntId ());
if ( c lie nt = = nu ll) { t hro w n ew Inv alid Cli ent Exc ep tion ("C lien t n ot f ou nd: " + cli ent Aut h.g etC lien tId ()); }
OA uth 2Ac ce ssToke nE ntit y to ke n = ne w O Au th2 Ac ces sTo ken En tity ();/ /acc es sTo ken Fac to ry.cr eat eNe wA cce ss Tok en( );
// a tta ch the c li ent tok en .se tCl ient (c li ent );
// i nhe rit the sc ope fro m the au th, but ma ke a n ew se t so it is //n ot u nm od ifia ble . Un mo difi ab les do n't pla y n ice ly w ith Ec lips eli nk , wh ich //w ant s to u se t he c lo ne ope ra tion . Se t< S ys tem Sc ope > sco pe s = sc op eSe rvi ce. fro mSt ring s (c lie ntA uth .ge tSc ope ());
// r em ove a ny o f th e s pe cia l s ys te m sco pe s s c ope s = s cop eS erv ice .rem o veR ese rve dS cop es (sc ope s );
tok en .se tSc ope (sc op eSe rvi ce .toS trin gs ( sco pe s )) ;
// m ak e i t e xpir e if ne ces sa ry if ( c lie nt. ge tAcc es sTo ken Va lid ityS eco nd s () != nu ll && cl ien t.ge tAc ce ssToke nV alid ity Se con ds ( ) > 0) { D ate ex pi ratio n = n ew Dat e(S ys t em .cu rren tTim eM il lis() + ( c lie nt.g etA cc es sTo ken Val idit yS eco nd s () * 10 00 L)) ; t oke n.s et Exp irat ion (ex pira tio n); }
// a tta ch the au tho riza tio n s o t hat we can lo ok it u p la ter Au the ntic at ionH old erE nti ty a ut hHo lde r = ne w A uth ent ica tion Ho lde rEn tity (); au thH old er. setA uth en tica tio n(a uth ent ica tion ); au thH old er = a uth ent ica tion Ho lde rRe pos ito ry.s av e(au thH old er) ;
tok en .se tAu the ntic ati onH old er (aut hHo lde r);
// a tta ch a r efre sh tok en, if t his c li ent is allo we d t o re que s t the m a nd the us er get s th e offli ne sco pe if ( c lie nt. isA llow Re fres h() && to ken .ge tSc ope ().c on tain s (S ys tem Sc op eSe rvic e.OF FL INE_ AC CES S)) { O Au th2 Re fres hTo ken En tity sa ved Re fres hTo ke n = cr eat eRe fre shTok en(c lie nt, aut hHo ld er);
t oke n.s et Refr esh Tok en (sa ve dRe fres hTo ke n); }
OA uth 2Ac ce ssToke nE ntit y e nh anc edToke n = (O Au th2 Acc es sTo ken En tity ) to ken En han ce r.en ha nce (to ken , a uth ent ica tion );
OA uth 2Ac ce ssToke nE ntit y s av edTo ke n = to ken Re pos ito ry.s ave Ac ce ssTo ke n(e nha nc ed Toke n);
//A dd app ro ved s it e re fer enc e, if a ny OA uth 2Re qu es t ori gin alA uth Re que s t = a uth Hol de r.ge tAu the ntic ati on ().ge tOA uth 2R equ es t();
if ( orig ina lA uthR eq ues t.g etE xte ns i ons () ! = n ull && ori gin alA uth Req ue s t.g etE xte ns ion s () .con tai nsK ey ("ap pr ove d_ s ite ")) {
L on g a pId = Lon g.pa rse Lon g((S trin g) o rigi na lAu thR equ es t.ge tEx te ns io ns ().g et("a pp ro ved _ s i te") ); A pp rov ed Site ap = app rov ed Site Se rvic e.g etB yI d(ap Id) ; S et< OA ut h2A cce ss Tok enE nt ity> ap Tok en s = a p.ge tAp pro ve dAc ce ssToke ns (); a pTo ke ns .add (sa ve dTo ken ); a p.s etA pp rov edA cc ess Tok en s (a pTo ken s ); a pp rov ed Site Ser vic e.s ave (a p);
}
if ( sav ed Tok en. get Ref res hTo ke n() ! = n ull ) { t oke nR ep os it ory. sav eR efre sh Tok en( sav ed Tok en .get Ref res hTo ken ()) ; // m ak e s ure we s ave an y c han ge s t hat mig ht hav e b ee n e nha nc ed }
ret urn sa ve dTok en ; }
th row ne w A ut hen tica tio nCr ede nt ials Not Fou nd Exc ep tion ("N o a uth ent ica tion cr ede nti als fo und ");}
priv ate OA uth 2R efre sh Tok enE nti ty crea teR efr esh Tok en (Cli ent Det ails En tity c li ent , Au the nti ca tion Hol der Ent ity au thHo lde r) { O Aut h2R efr es hTok en Ent ity refr es hTok en = new OA ut h2R efre sh Tok enE nt ity() ; //r efre sh Tok en Fact ory. cre ate New Re fres hTo ke n(); JW TC lai ms Se t.Bu ilde r re fre shC la ims = new JW TC lai msS et. Bui lde r();
// ma ke it e xp ire if n ece ss ary if (c l ien t.ge tR efre shToke nV alid ity Sec on ds ( ) != nu ll) { Da te e xp ira tion = new Da te( Sy s tem .cu rren tTi meM il lis() + (c l ien t.g etR efre shToke nV ali dity Se con ds ( ) * 10 00L )); ref res hTo ke n.se tEx pir atio n(e xp irat ion ); ref res hCl aim s .e xp irat ion Tim e( exp irat ion ); }
// se t a ran do m id en tifie r re fre shC lai ms .jwt ID(U UID .ran dom UU ID().t oSt ring ());
// TO DO: add is su er fi eld s , s ign atu re to JWT
Pla inJ WT refr es hJw t = ne w P lain JW T(r efre shC lai ms . bu ild ()); re fre shToke n. setJ wt(r efre sh Jwt) ;
// Add th e a uth ent ica tion re fre shToke n. setA uth en tica tio nH olde r(a uth Hol der ); re fre shToke n. setC lie nt(c lie nt);
// sa ve the to ken firs t s o th at we can se t it to a m em be r of the ac ce ss tok en (NO TE: is thi s s t ep nec es sar y? ) O Aut h2R efr es hTok en Ent ity sav ed Ref res hTo ken = to ken Rep os itor y.sa ve Ref res hTo ken (re fre shTo ke n); re tur n s ave dR efre sh Tok en;}
@O ver ridepub lic OA uth 2A cce ssToke nE ntit y r efre shA cc ess Tok en (Str ing ref res hTo ke nVa lue , To ken Re qu es t aut hRe qu es t ) th row s A uth ent ica tio nEx cep tio n {
O Aut h2R efr es hTok en Ent ity refr es hTok en = cle arE xp ired Ref res hTo ken (to ken Re pos ito ry.g etR efre sh Tok enB yV alu e(re fre shToke nV alu e));
if (re fres hTo ke n = = nul l) { thr ow new In val idTo ke nEx ce pti on(" Inv alid re fres h toke n: " + ref res hTo ken Va lue ); }
C lien tDe tai lsE ntit y c lien t = re fre shTo ke n.g etC lien t() ;
A uth ent ica tio nHo lde rEn tity au thH old er = re fre shTok en.g etA uth en tica tio nHo lde r();
// ma ke su re that the c l ien t re qu es ti ng the tok en is the on e w ho own s the refr esh to ken C lien tDe tai lsE ntit y re qu es t ing Cli ent = c lie ntD eta ils Serv ice .lo adC lie ntB yCl ien tId( aut hRe qu es t .ge tCli ent Id() ); if (!c lien t.g etC lien tId ().e qua ls ( req ues tin gCl ien t.ge tC lien tId( ))) { tok en Rep os itor y.re mo veR efr es hTok en (ref res hTo ke n); thr ow new In val idC lien tEx ce pti on(" Clie nt doe s n ot own th e p res ent ed refr esh to ken "); }
// Ma ke sur e t his c lie nt allo ws ac ces s t oke n r efre sh ing if (!c lien t.is Al lowR efr esh ()) { thr ow new In val idC lien tEx ce pti on(" Clie nt doe s n ot allo w r efre sh ing ac ces s t oke n!" ); }
// c le ar out an y a cce ss tok en s if (c l ien t.is Cle arA cce ss Tok ens On Ref res h()) { tok en Rep os itor y.c l ear Acc es sTo ken sF orR efre sh Tok en( refr esh Tok en ); }
if (re fres hTo ke n.is Ex pire d() ) { tok en Rep os itor y.re mo veR efr es hTok en (ref res hTo ke n); thr ow new In val idTo ke nEx ce pti on(" Exp ire d re fre sh tok en: " + re fres hToke nVa lue ); }
O Aut h2A cc es sTok en Ent ity tok en = n ew OA uth 2Ac ce ssToke nE ntit y();
// ge t th e s tor ed s co pes fro m the au the ntic ati on ho lder 's a uth ori zat ion req ue s t; the se are the sc op es ass oc iate d w ith the re fre sh t oke n S et< Str ing > refre sh Sco pe sRe qu es t ed = n ew Ha sh Set< > (ref res hTo ke n.ge tAu the nti cat ion Hol der ().g etA uth en tica tion ().g etO Au th2 Req ue s t() .ge tSc op e()); S et< Sy s te mS cop e> re fres hS co pes = sco pe Ser vic e.fr om Stri ngs (re fre shS cop es Req ue s te d); // rem ov e a ny of the sp eci al s ys tem sc op es re fre shS co pe s = sc ope Se rvic e. rem ove Re ser ved Sc ope s (r efre sh Sco pe s );
S et< Str ing > sco peR eq ues ted = au thR equ es t.ge tS cop e() = = nu ll ? n ew H as hSe t< Stri ng > () : ne w H as hSe t< > (a uth Re que s t. ge tSco pe ()); S et< Sy s te mS cop e> sc op e = s cop eSe rvi ce. from S tring s (s co peR eq ue s ted );
// rem ov e a ny of the sp eci al s ys tem sc op es s cop e = s co peS erv ice .rem ov eR ese rve dS cop es (sc ope );
if (sc op e != n ull && !sc ope .is Em pty ()) { // e ns ure a prop er sub se t of sc ope s if ( refr esh Sc ope s ! = n ull && re fres hSc op es . con ta insA ll(s co pe) ) { / / se t th e sco pe of t he new a cce ss tok en if re qu es t ed t oke n.s et Sco pe( sco pe Ser vic e.to Str ing s (s cop e) ); } e lse { S trin g e rro rMs g = "U p-s co pin g is no t a llow ed ."; lo gge r.er ror( erro rMs g) ; t hro w n ew Inv alid Sc ope Ex ce ptio n(e rror Ms g); } } els e { // o the rwi se inh erit the sc op e o f th e re fre sh tok en (if i t's the re - - th is can ret urn a n ull sc ope se t) tok en .se tSc ope (sc op eSe rvi ce .toS trin gs ( refr esh Sc ope s )) ; }
to ke n.s etC lie nt(c lien t);
if (c l ien t.ge tA cce ssToke nV alid ity Sec on ds ( ) != nu ll) { Da te e xp ira tion = new Da te( Sy s tem .cu rren tTi meM il lis() + (c l ien t.g etA cce ssToke nV ali dity Se con ds ( ) * 10 00L )); tok en .se tEx pira tio n(e xpi rati on ); }
if (c l ien t.is Re use Ref res hTo ken ()) { // i f th e c lie nt re -us es ref res h t oke ns , do tha t tok en .se tRe fres hTo ke n(re fre sh Toke n); } els e { // o the rwi se , ma ke a n ew ref res h to ke n OA uth 2Re fre shToke nE ntit y n ew Refr esh = cre ate Re fres hTo ke n(c lien t, auth Ho lde r); tok en .se tRe fres hTo ke n(n ewR ef resh );
// c lea n u p the old ref res h to ke n tok en Rep os itor y.re mo veR efr es hTok en (ref res hTo ke n); }
to ke n.s etA uth ent ica tion Ho lde r(a uthH old er) ;
to ke nEn ha nc er.e nha nc e(to ke n, auth Ho lde r.ge tAu th enti cat ion ());
to ke nRe po s it ory.s av eAc ce ssTok en(t oke n);
re tur n to ke n;
}
@O ver ridepub lic OA uth 2A uthe nti cat ion loa dA uth ent ica tion (St rin g ac ce ssToke nV alu e) t hro ws Aut hen tic atio nE xce pti on {
O Aut h2A cc es sTok en Ent ity acc es sTo ken = cle arE xp ired Ac ces sTo ke n(t oke nRe po s ito ry.g et Acc ess Tok en ByV al ue(a cc ess Tok en Va lue) );
if (ac ce ssTok en = = nu ll) { thr ow new In val idTo ke nEx ce pti on(" Inv alid ac ce ss tok en: " + ac ce ss Toke nV alu e); } els e { ret urn ac ce ssTo ke n.g etA uth en tica tion Ho lde r().g et Auth en tica tio n(); }}
/* * * G et an acc es s to ke n fr om its to ken va lue . * /@O ver ridepub lic OA uth 2A cce ssToke nE ntit y r ead Acc es sTo ken (S tring ac ce ssToke nV alu e) t hro ws Aut he ntic atio nE xce pti on { O Aut h2A cc es sTok en Ent ity acc es sTo ken = cle arE xp ired Ac ces sTo ke n(t oke nRe po s ito ry.g et Acc ess Tok en ByV al ue(a cc ess Tok en Va lue) ); if (ac ce ssTok en = = nu ll) { thr ow new In val idTo ke nEx ce pti on(" Acc es s to ke n f or v alu e " + a cc es sTok en Val ue + " wa s n ot f oun d") ; } els e { ret urn ac ce ssTo ke n; }}
/* * * G et an acc es s to ke n b y it s a uth ent ica tion ob jec t. * /@O ver ridepub lic OA uth 2A cce ssToke nE ntit y g etA cce ss Tok en( OA uth2 Au the ntic ati on aut hen tic atio n) { // TO DO: imp lem e nt t his aga ins t th e new se rvic e ( # 8 25 ) thr ow new Un su pp orte dOp era tion Ex ce ptio n(" Una ble to lo ok u p a cc ess to ke n fro m aut hen tic ati on o bje ct. ");}
/* * * G et a re fre sh tok en by its tok en val ue. * /@O ver ridepub lic OA uth 2R efre shToke nE ntit y g etR efre sh Tok en( Str ing refr esh Tok en Va lue) thr ows Au the nt icat ion Exc ep tion { O Aut h2R efr es hTok en Ent ity refr es hTok en = tok enR ep os i tory.ge tRe fres hToke nBy Va lue (ref res hTo ken Va lue ); if (re fres hTo ke n = = nul l) { thr ow new In val idTo ke nEx ce pti on(" Ref res h to ke n f or v alu e " + r efre sh Tok enV alu e + " wa s no t fo un d"); } e lse { ret urn ref res hTo ken ; }}
/* *
* R ev oke a ref resh to ken an d a ll acc ess to ken s i s s ued to it. * /@O ver ridepub lic vo id r ev oke Ref res hTo ken (O Auth 2R efre sh Tok en Enti ty r efre sh Tok en ) { to ke nRe po s it ory.c lea rAc ce ssTok ens For Ref res hTo ke n(re fres hTo ke n); to ke nRe po s it ory.r em ove Re fres hToke n(re fre shToke n) ;}
/* * * R ev oke an a cce ss tok en.
* /@O ver ridepub lic vo id r ev oke Acc es sTo ken (O Auth 2A cce ss Tok en Enti ty a cc ess Tok en ) { to ke nRe po s it ory.r em ove Ac ces sToke n(a cce ss Tok en );}
/* ( non -Ja vad oc ) * @ se e o rg. mi tre.o au th2 .se rvic e. OAu th2 Tok enE nti tyS erv ice # g etA cce ss Tok ens Fo rCli ent (or g.m itre .oa uth 2.m od el.C lie ntD eta ilsE nt ity) * /@O ver ridepub lic Lis t< OA uth2 Ac ces sTo ke nE ntity > get Acc es sTo ken sF orC lien t(C lie ntDe tai lsE ntit y c lie nt) { re tur n to ke nR epo s ito ry.g etA cc es sTok en sFo rCl ien t(c lien t);}
/* ( non -Ja vad oc ) * @ se e o rg. mi tre.o au th2 .se rvic e. OAu th2 Tok enE nti tyS erv ice # g etR efre sh Tok ens Fo rCli ent (or g.m itre .oa uth 2.m od el.C lie ntD eta ilsE nt ity) * /@O ver ridepub lic Lis t< OA uth2 Re fres hTo ke nE ntity > get Ref res hTo ken sF orC lien t(C lie ntDe tai lsE ntit y c lie nt) { re tur n to ke nR epo s ito ry.g etR efr es hTok en sFo rCl ien t(c lien t);}
/* * * C lea rs out ex pire d t oke ns an d a ny aba nd one d a ut hen tica tio n o bje cts * /@O ver ridepub lic vo id c le arEx pir edToke ns () { log ge r.de bug ("C lea nin g o ut all e xp ired to ke ns" ); // ge t al l th e d upl ica ted tok en s fi rs t to m ai nta in c on s is ten cy to ke nRe po s it ory.c lea rDu pli cat eA cce ssToke ns (); to ke nRe po s it ory.c lea rDu pli cat eR efre shToke ns ();
C olle cti on< O Auth 2A cce ss Tok en Enti ty> ac ce ssTok ens = get Exp ire dA cce ssToke ns (); if (ac ce ssTok ens .s iz e() > 0) { log ger .inf o("F ou nd " + ac ces sTo ke ns . s iz e() + " ex pire d a cc ess to ken s") ; } fo r (O Au th2 Ac ces sTo ken En tity oA uth 2Ac ce ssToke nE ntit y : acc es sTo ke ns ) { try { r evo ke Ac ces sTo ken (oA uth 2A cce ss Tok enE nti ty) ; } c atc h ( Ille gal Arg um ent Exc ep tion e) { / /An ID tok en is d ele ted wi th its c orr esp on din g a cce ss tok en , bu t t hen the ID tok en is on the lis t of ex pir ed t oke ns as we ll a nd the re i s / /no thin g in p lac e to di s tin gu ish it f rom an y o th er. / /An att em pt t o d ele te a n a lre ady de let ed tok en retu rns an er ror, s t opp ing the c l ean up de ad. We ne ed it to k eep go ing . } }
C olle cti on< O Auth 2R efre sh Tok en Enti ty> re fres hTo ke ns = g etE xp ired Re fres hTo ke ns ( ); if (re fres hTo ke ns . s iz e() > 0 ) { log ger .inf o("F ou nd " + ref res hTo ken s .s iz e() + " exp ire d re fre sh tok ens "); } fo r (O Au th2 Re fres hTo ken En tity oA uth 2Re fre shToke nE ntit y : refr esh Tok en s ) { rev ok eRe fre shToke n(o Au th2 Re fres hTo ken En tity ); }
C olle cti on< A uthe nti cat ion Hol de rEnt ity> a uth Hol de rs = ge tOr pha ne dA uthe nti cat ion Hol de rs (); if (au thH old er s .s i ze( ) > 0) { log ger .inf o("F ou nd " + au thH old ers .s iz e( ) + " or pha ne d a uth ent ica tion ho lde rs "); } fo r(A uth ent ica tion Ho lde rEn tity au thH old er : au thH old ers ) { au the ntic at ionH old erR ep os i tor y.rem ov e(a uth Ho lde r); }}
priv ate Co lle cti on< OA uth 2Ac ce ss Toke nE ntit y> ge tEx pire dA cce ss Tok en s () { re tur n S ets .ne wHa sh Set(tok enR ep os itor y.ge tAll Exp ire dA cce ss Toke ns ());}
priv ate Co lle cti on< OA uth 2Re fre sh Toke nE ntit y> ge tEx pire dR efre sh Tok en s () { re tur n S ets .ne wHa sh Set(tok enR ep os itor y.ge tAll Exp ire dR efre sh Toke ns ());}
priv ate Co lle cti on< Au the ntic ati on Hold erE nti ty> ge tO rpha ne dAu the nti ca tion Hol der s () { re tur n S ets .ne wHa sh Set(aut hen tic ati onH old erR epo s i tory.ge tOrp han ed Au the ntic ati onH old ers ());}
/* ( non -Ja vad oc ) * @ se e o rg. mi tre.o au th2 .se rvic e. OAu th2 Tok enE nti tyS erv ice # s ave Ac ce ssTo ke n(o rg.m itr e.o aut h2. mo del .OA uth 2Ac ce ssToke nE nti ty) * /@O ver ridepub lic OA uth 2A cce ssToke nE ntit y s ave Ac ces sTo ke n(O Aut h2A cc ess Tok en Ent ity acc es sTo ke n) { re tur n to ke nR epo s ito ry.s av eAc ce ssToke n(a cc ess To ken );}
/* ( non -Ja vad oc ) * @ se e o rg. mi tre.o au th2 .se rvic e. OAu th2 Tok enE nti tyS erv ice # s ave Re fre shTo ke n(o rg.m itr e.o aut h2. mo del .OA uth 2Re fre shToke nE nti ty) * /@O ver ridepub lic OA uth 2R efre shToke nE ntit y s ave Re fres hTo ke n(O Aut h2R efr esh Tok en Ent ity refr esh Tok en ) { re tur n to ke nR epo s ito ry.s av eRe fre shToke n(r efre sh Tok en) ;}
/* * * @ retu rn the tok en Enh an cer * /pub lic Tok en En han cer ge tTok en En han cer () { re tur n to ke nE nha nce r;}
/* * * @ param tok enE nh anc er the tok en Enh an ce r to set * /pub lic vo id s et Toke nE nha nc er(Tok enE nha nc er t oke nE nha nc er) { th is . tok enE nh anc er = t oke nE nh anc er;}
/* ( non -Ja vad oc ) * @ se e o rg. mi tre.o au th2 .se rvic e. OAu th2 Tok enE nti tyS erv ice # g etA cce ss Tok enF orI dTo ken (o rg.m itre .oa uth 2.m o del. OAu th2 Ac ces sToke nEn tity ) * /@O ver ridepub lic OA uth 2A cce ssToke nE ntit y g etA cce ss Tok enF or IdTo ken (OA uth 2A cc ess Tok enE nti ty i dTo ken ) { re tur n to ke nR epo s ito ry.g etA cc es sTok en For IdTo ke n(i dTok en );}
@O ver ridepub lic OA uth 2A cce ssToke nE ntit y g etR egi s tra tio nAc ce ssToke nF orC lien t(C lien tDe tai lsE ntit y c lien t) { L is t< OA uth 2A cce ss Tok enE nti ty> al lTok en s = ge tA cce ssToke ns For Cli ent( c lie nt) ;
fo r (O Au th2 Ac ces sTo ken En tity to ken : a llTo ken s ) { if ( (tok en .ge tSc ope ().c on tain s ( Sys tem Sc ope Se rvi ce.RE GIS TR ATI ON_ TO KEN _ S COP E) || tok en. get Sc ope ().c on tain s (S ys tem Sc ope Ser vic e.RE SOU RCE _ T OK EN_ SC OPE)) && to ke n.ge tSc op e(). s iz e() = = 1) { / / if it o nly ha s th e r egi s tra tio n s cop e, the n it 's a re gis trat ion tok en r etu rn t ok en; } }
re tur n n ull;}
www.luxoft.com 16
Почему так получается? Что делать?
Сильная связАнность, большие классы? Нужно лучше писать код. Unit-тесты помогут выявить
проблемы. Используйте @Autowired на
конструкторах, сеттерах, методах.
public class ApprovedSiteAPI {
public static final String URL = RootController.API_URL + "/approved";
@Autow ired private ApprovedSiteService approvedSiteService; @Autow ired private OAuth2TokenEntityService tokenServices; @Autow ired private OAuth2TokenEntityService tokenServices; @Autow ired private ClientDetailsEntityService clientService; @Autow ired private IntrospectionResultAssembler introspectionResultAssembler; @Autow ired private UserInfoService userInfoService; @Autow ired private ResourceSetService resourceSetService;
/** * Delete an approved site * * / @RequestMapping(value="/{id}", method = RequestMethod.DELETE) public String deleteApprovedSite(@PathVariable("id") Long id, ModelMap m, Principal p) { ApprovedSite approvedSite = approvedSiteService.getById(id);
if (approvedSite == null) { logger.error("deleteApprovedSite failed; no approved site found for id: " + id); m .put(HttpCodeView.CODE, HttpStatus.NO T_FOUND); m .put(JsonErrorView.ERRO R_MESSAGE, "Could not delete approved site. The requested approved site w ith id: " + id + " could not be found."); return JsonErrorView.VIEWNAME; } else if (!approvedSite.getUserId().equals(p.getName())) { logger.error("deleteApprovedSite failed; principal " + p.getName() + " does not own approved site" + id); m .put(HttpCodeView.CODE, HttpStatus.FORB IDDEN); m .put(JsonErrorView.ERRO R_MESSAGE, "You do not have permission to delete this approved site. The approved site decision will not be deleted."); return JsonErrorView.VIEWNAME; } else { m .put(HttpCodeView.CODE, HttpStatus.O K); approvedSiteService.remove(approvedSite); }
return HttpCodeView.VIEWNAME; }
@Overridepublic OAuth2AccessTokenEntity c reateAccess Tok en(OAuth2Authentic ation authentic ation) throws Authentic ationExc eption, Inva lidClientException { if (authenti cation != null && authentication.getOAuth2Reques t() != nul l) { // l ook up our c lient OAuth2Request cli entAuth = authenti cation.getOAuth2Request();
Cli entDetail sEntity cli ent = cli entDeta ils Servic e.l oadClientByClientId(cli entAuth.getClientId());
if (client == null) { throw new InvalidCli entExc eption("Client not found: " + cli entAuth.getClientId()); }
OAuth2Ac cessTokenEntity token = new OAuth2Ac ces sTokenEntity ();/ /acc es sTokenFac tory.createNewAccess Tok en();
// a ttach the cli ent tok en.setCl ient(cli ent);
// i nherit the sc ope from the auth, but make a new set so it is //not unmodifiable . Unmodifiables don't play nice ly with Ec lips eli nk , which //wants to use the clone operation. Set<Sys temSc ope> scopes = sc opeServi ce. fromStrings(c lientAuth.getSc ope());
// remove any o f the s pecia l s ystem scopes sc opes = s copeServ ice .removeReservedScopes (sc opes);
tok en.setSc ope(sc opeServi ce .toStrings(scopes));
// mak e i t expire if neces sary if (client. getAcc es sTokenVa liditySeconds() != null && cl ient.getAc cessTokenValiditySeconds() > 0) { Date expi ration = new Date(System.currentTimeMil lis () + (client.getAcc es sTokenVal iditySeconds() * 1000L)); token.s etExpiration(expira tion); }
// a ttach the authorization s o that we can look it up la ter Authentic ationHolderEnti ty authHo lder = new AuthenticationHo lderEntity (); authHolder. setAuthentication(authentication); authHolder = authenticationHo lderRepos itory.s ave(authHolder);
tok en.setAuthentic ati onHolder(authHo lder);
// a ttach a refresh tok en, if this cli ent is allowed to request them and the us er gets the offli ne scope if (client. isAllowRefres h() && token.getSc ope().c ontains(Sys temSc opeServic e. OF FL INE_ ACCESS)) { OAuth2Refres hTokenEntity savedRefres hToken = createRefreshTok en(c lient, authHo lder);
token.s etRefreshTok en(savedRefres hToken); }
OAuth2Ac cessTokenEntity enhanc edToken = (OAuth2Acc es sTokenEntity ) tokenEnhancer.enhance(token, authentication);
OAuth2Ac cessTokenEntity s avedToken = tokenRepos itory.s aveAc cessToken(enhanc edToken);
//Add approved site re ferenc e, if any OAuth2Request ori ginalAuthRequest = authHol der.getAuthentic ati on().getOAuth2Reques t();
if (origina lAuthReques t.getExtensi ons () != null && ori ginalAuthRequest.getExtens ions().contai nsKey ("approved_s ite")) {
L ong apId = Long. parseLong ((String) o rigi na lAuthReques t.getEx tensions ().get("approved_si te")); ApprovedSite ap = approvedSiteServic e.getByI d(apId); Set< OAuth2Access Tok enEntity> apTok ens = ap.getApprovedAc cessTokens (); apTokens .add(savedToken); ap.s etApprovedAcc ess Tok ens(apTokens); approvedSiteServic e.s ave(ap);
}
if (savedTok en. getRef res hToken() != null ) { tokenRepository. saveRefreshTok en(savedTok en.getRef res hToken()); // mak e s ure we s ave any c hanges that might have been enhanc ed }
return savedTok en; }
throw new AuthenticationCredentials NotFoundExc eption("No authentication credenti als found");}
private OAuth2RefreshTok enEnti ty createRefreshTok en(Cli entDetails Entity cli ent, Authenti cationHol derEntity authHo lder) { OAuth2Refres hTok enEntity refres hTok en = new OAuth2RefreshTok enEntity(); //refreshTok enFactory. createNewRefres hToken(); JWTClai ms Set.Builder re freshCla ims = new JWTClai msSet. Bui lder();
// make it expire if necess ary if (cl ient.getRefreshTokenValiditySec onds() != null) { Date expira tion = new Date(System. currentTi meMil lis () + (cl ient.getRefreshTokenVali ditySeconds() * 1000L )); ref res hToken.setExpiration(expiration); ref res hCl aims.expirationTime(expiration); }
// set a random identifier re freshClai ms .jwtID(UUID. randomUUID().toString());
// TODO: add is suer fields, s ignature to JWT
Pla inJ WT refres hJwt = new P lainJWT(refreshClai ms. build()); re freshToken. setJ wt(refreshJwt);
// Add the authentication re freshToken. setAuthenticationHolder(authHol der); re freshToken. setClient(c lient);
// save the token firs t s o that we can set it to a member of the ac cess tok en (NOTE: is thi s step nec es sary? ) OAuth2Refres hTok enEntity savedRef res hToken = tokenRepos itory.saveRef res hToken(re freshToken); re turn s avedRefreshTok en;}
@Overridepublic OAuth2AccessTokenEntity refreshAcc ess Tok en(String ref res hTokenVa lue, TokenRequest authRequest) throws AuthenticationException {
OAuth2Refres hTok enEntity refres hTok en = clearExpiredRef res hToken(tokenRepos itory.getRefreshTok enByValue(re freshTokenValue));
if (re fres hToken = = nul l) { throw new Inval idTokenExcepti on("Invalid re fres h token: " + ref res hTokenVa lue); }
ClientDetai lsEntity c lient = re freshToken.getClient();
AuthenticationHo lderEntity authHolder = re freshTok en.getAuthenticationHo lder();
// make sure that the cl ient requesti ng the tok en is the one who owns the refresh token ClientDetai lsEntity requestingCli ent = c lientDeta ils Serv ice .loadClientByCl ientId(authRequest.getCli entId()); if (!c lient.getClientId().equa ls(reques tingCl ient.getClientId())) { tok enRepos itory.removeRefres hTok en(ref res hToken); throw new Inval idClientExcepti on("Client does not own the pres ented refresh token"); }
// Make sure this client allows ac ces s token refreshing if (!c lient.is Al lowRefresh()) { throw new Inval idClientExcepti on("Client does not allow refreshing ac ces s token!"); }
// clear out any access tok ens if (cl ient.is ClearAccess Tok ens OnRef res h()) { tok enRepos itory.cl earAcc es sTokensF orRefreshTok en(refreshTok en); }
if (re fres hToken.is Expired()) { tok enRepos itory.removeRefres hTok en(ref res hToken); throw new Inval idTokenExcepti on("Expired re fresh tok en: " + re fres hTokenVa lue); }
OAuth2Acc es sTok enEntity tok en = new OAuth2Ac cessTokenEntity();
// get the s tored s copes from the authentic ati on ho lder's authori zation request; these are the sc opes ass oc iated with the re fresh token Set< String> refreshScopesRequested = new HashSet< > (ref res hToken.getAuthenti cationHol der().getAuthentication().getOAuth2Request().getSc ope()); Set< SystemScope> re fres hScopes = scopeServic e.fromStri ngs (re freshScopes Requested); // remove any of the speci al s ys tem sc opes re freshScopes = sc opeServic e. removeReservedSc opes(refreshScopes);
Set< String> scopeReques ted = authReques t.getScope() == null ? new Has hSet< Stri ng>() : new Has hSet< >(authRequest. getScope()); Set< SystemScope> sc ope = s copeServi ce. fromStrings(s copeRequested);
// remove any of the speci al s ys tem sc opes s cope = s copeServ ice .removeReservedScopes (sc ope);
if (sc ope != null && !sc ope.is Empty ()) { // ens ure a proper subset of sc opes if (refreshSc opes != null && re fres hSc opes. conta insAll(s cope)) { / / set the scope of the new access tok en if requested token.s etScope(scopeServic e.toStrings(s cope)); } e lse { String errorMs g = "Up-s coping is not a llowed."; logger.error(errorMs g); throw new InvalidSc opeException(errorMs g); } } els e { // o therwi se inherit the sc ope o f the re fresh tok en (if i t's there - - this can return a null sc ope set) tok en.setSc ope(sc opeServi ce .toStrings(refreshSc opes)); }
token.s etClient(c lient);
if (cl ient.getAccessTokenValiditySec onds() != null) { Date expira tion = new Date(System. currentTi meMil lis () + (cl ient.getAccessTokenVali ditySeconds() * 1000L )); tok en.setExpira tion(expi rati on); }
if (cl ient.is ReuseRef res hToken()) { // i f the c lient re -us es ref res h tokens, do that tok en.setRefres hToken(re freshToken); } els e { // o therwi se , make a new ref res h token OAuth2RefreshTokenEntity newRefresh = createRefres hToken(c lient, authHo lder); tok en.setRefres hToken(newRef resh);
// c lean up the old ref res h token tok enRepos itory.removeRefres hTok en(ref res hToken); }
token.s etAuthenticationHo lder(authHolder);
tokenEnhanc er.enhanc e(token, authHo lder.getAuthenti cation());
tokenRepository.s aveAc cessTok en(token);
re turn token;
}
@Overridepublic OAuth2Authenti cation loadAuthentication(String ac cessTokenValue) throws Authentic ationExcepti on {
OAuth2Acc es sTok enEntity acc es sToken = clearExpiredAc ces sToken(tokenRepository.getAcc ess Tok enByVal ue(acc ess Tok enVa lue));
if (ac cessTok en = = null) { throw new Inval idTokenExcepti on("Invalid ac cess tok en: " + ac cess TokenValue); } els e { return ac cessToken.getAuthenticationHo lder().getAuthentication(); }}
/** * Get an acc es s token from its token va lue . */@Overridepublic OAuth2AccessTokenEntity readAcc es sToken(String ac cessTokenValue) throws Authentic ationExcepti on { OAuth2Acc es sTok enEntity acc es sToken = clearExpiredAc ces sToken(tokenRepository.getAcc ess Tok enByVal ue(acc ess Tok enVa lue)); if (ac cessTok en = = null) { throw new Inval idTokenExcepti on("Acc es s token for value " + acc es sTok enVal ue + " was not found"); } els e { return ac cessToken; }}
/** * Get an acc es s token by its authentication objec t. */@Overridepublic OAuth2AccessTokenEntity getAccess Tok en(OAuth2Authentic ati on authentic ation) { // TODO: implement this aga ins t the new servic e (#825) throw new UnsupportedOperationException("Unable to look up acc ess token from authentic ati on object. ");}
/** * Get a re fresh tok en by its tok en val ue. */@Overridepublic OAuth2RefreshTokenEntity getRefreshTok en(String refreshTok enVa lue) throws AuthenticationExc eption { OAuth2Refres hTok enEntity refres hTok en = tok enReposi tory.getRefres hTokenByVa lue(ref res hTokenVa lue); if (re fres hToken = = nul l) { throw new Inval idTokenExcepti on("Ref res h token for value " + refreshTok enValue + " was not found"); } e lse { return ref res hToken; }}
/** * Revoke a ref resh token and a ll acc ess tokens i ss ued to it. */@Overridepublic vo id revokeRef res hToken(OAuth2RefreshTok enEnti ty refreshTok en) { tokenRepository.c learAc cessTok ens ForRef res hToken(re fres hToken); tokenRepository.removeRefres hToken(re freshToken);}
/** * Revoke an access tok en. */@Overridepublic vo id revokeAcc es sToken(OAuth2Access Tok enEnti ty acc ess Tok en) { tokenRepository.removeAc ces sToken(access Tok en);}
/* (non-Javadoc ) * @see org. mi tre.oauth2.servic e. OAuth2Tok enEnti tyServ ice#getAccess Tok ens ForCli ent(org.mitre .oauth2.model.ClientDeta ilsEntity) */@Overridepublic Lis t< OAuth2Ac ces sTokenEntity> getAcc es sTokensF orClient(ClientDetai lsEntity c lient) { re turn tokenRepository.getAcc es sTok ensForCl ient(c lient);}
/* (non-Javadoc ) * @see org. mi tre.oauth2.servic e. OAuth2Tok enEnti tyServ ice#getRefreshTok ens ForCli ent(org.mitre .oauth2.model.ClientDeta ilsEntity) */@Overridepublic Lis t< OAuth2Refres hTokenEntity> getRef res hTokensF orClient(ClientDetai lsEntity c lient) { re turn tokenRepository.getRefres hTok ensForCl ient(c lient);}
/** * Clears out expired tokens and any abandoned authentication objects */@Overridepublic vo id c learExpiredTokens () { logger.debug("Cleaning out all expired tokens"); // get al l the dupl icated tok ens first to mai nta in c onsis tency tokenRepository.c learDupli cateAccessTokens (); tokenRepository.c learDupli cateRefreshTokens ();
Collecti on< OAuth2Access Tok enEnti ty> ac cessTok ens = getExpiredAccessTokens (); if (ac cessTok ens .siz e() > 0) { logger .info("F ound " + ac ces sTokens. siz e() + " expired acc ess tokens"); } fo r (OAuth2Ac ces sTokenEntity oAuth2Ac cessTokenEntity : acc es sTokens) { try { revokeAc ces sToken(oAuth2Access Tok enEnti ty); } c atc h ( Illegal ArgumentExc eption e) { / /An ID tok en is deleted wi th its c orresponding access tok en, but then the ID tok en is on the lis t of expired tokens as well and there i s / /nothing in plac e to di stinguish it f rom any other. / /An attempt to delete an a lready de leted tok en returns an error, stopping the cl eanup dead. We need it to k eep go ing. } }
Collecti on< OAuth2RefreshTok enEnti ty> re fres hTokens = getExpiredRefres hTokens(); if (re fres hTokens. siz e() > 0) { logger .info("F ound " + ref res hTokens.s iz e() + " expired re fresh tok ens "); } fo r (OAuth2Refres hTokenEntity oAuth2RefreshTokenEntity : refreshTok ens) { revok eRefreshToken(oAuth2Refres hTokenEntity ); }
Collecti on< Authenti cationHol derEntity> authHol ders = getOrphanedAuthenti cationHol ders(); if (authHolders.si ze() > 0) { logger .info("F ound " + authHolders .siz e() + " orphaned authentication ho lders "); } fo r(AuthenticationHo lderEntity authHolder : authHolders ) { authentic ationHolderReposi tory.remove(authHo lder); }}
private Co llecti on< OAuth2Ac cess TokenEntity> getExpiredAccess Tok ens() { re turn Sets . newHashSet(tok enRepos itory.getAll ExpiredAccess Tokens ());}
private Co llecti on< OAuth2RefreshTokenEntity> getExpiredRefreshTok ens() { re turn Sets . newHashSet(tok enRepos itory.getAll ExpiredRefreshTokens ());}
private Co llecti on< Authentic ati onHolderEnti ty> getOrphanedAuthenti cationHol ders() { re turn Sets . newHashSet(authentic ati onHolderReposi tory.getOrphanedAuthentic ati onHolders ());}
/* (non-Javadoc ) * @see org. mi tre.oauth2.servic e. OAuth2Tok enEnti tyServ ice#s aveAc cessToken(org.mitre.oauth2. model .OAuth2Ac cessTokenEnti ty) */@Overridepublic OAuth2AccessTokenEntity s aveAc ces sToken(OAuth2Acc ess Tok enEntity acc es sToken) { re turn tokenRepository.s aveAc cessToken(acc ess Token);}
/* (non-Javadoc ) * @see org. mi tre.oauth2.servic e. OAuth2Tok enEnti tyServ ice#s aveRefreshToken(org.mitre.oauth2. model .OAuth2RefreshTokenEnti ty) */@Overridepublic OAuth2RefreshTokenEntity s aveRefres hToken(OAuth2RefreshTok enEntity refreshTok en) { re turn tokenRepository.s aveRefreshToken(refreshTok en);}
/** * @return the tok enEnhancer */public Tok enEnhancer getTok enEnhancer() { re turn tokenEnhancer;}
/** * @param tok enEnhanc er the tok enEnhancer to set */public vo id s etTokenEnhanc er(Tok enEnhanc er tokenEnhanc er) { this. tok enEnhanc er = tokenEnhanc er;}
/* (non-Javadoc ) * @see org. mi tre.oauth2.servic e. OAuth2Tok enEnti tyServ ice#getAccess Tok enF orI dToken(org.mitre .oauth2.model. OAuth2Ac ces sTokenEntity ) */@Overridepublic OAuth2AccessTokenEntity getAccess Tok enF orIdToken(OAuth2Acc ess Tok enEnti ty i dToken) { re turn tokenRepository.getAcc es sTok enForIdToken(i dTok en);}
@Overridepublic OAuth2AccessTokenEntity getRegi stra tionAc cessTokenF orClient(ClientDetai lsEntity c lient) { L ist< OAuth2Access Tok enEnti ty> al lTok ens = getAccessTokens ForCli ent(client);
fo r (OAuth2Ac ces sTokenEntity token : a llTokens) { if ((tok en.getSc ope().c ontains(Sys temSc opeServi ce. REGISTRATI ON_ TOKEN_SCOPE ) || tok en. getSc ope().c ontains(Sys temSc opeServic e.RESOURCE_TOKEN_ SCOPE )) && token.getSc ope(). siz e() == 1) { / / if it only has the regi stra tion s cope, then it 's a regis tration tok en return tok en; } }
re turn null;}
www.luxoft.com 17
Annotation-based конфигурация (–)
View
Domain
Data Source
DB
Infra
stru
ctur
e
www.luxoft.com 18
Annotation-based конфигурация (–)
Spring в Domain: невозможно отказаться от
Spring; сложности при reuse; нарушение архитектуры.
Что делать? JSR-330; не делать так.
@Inject @Autowired@Named @Component
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-standard-annotations
www.luxoft.com 19
Как не использовать Spring в Domain?
DB
View
DS
Domain
Infrastructure
www.luxoft.com 20
А где файл c бинами контекста?
Непонятно куда размещать чисто конфигурационный код.
С аннотациями @Component, @Service проблематично создать несколько бинов одного класса.
Сторонние классы без этих аннотаций.
Уменьшить связАннось.
www.luxoft.com 21
Java-based конфигурация@Configurationpublic class ApplicationConfig {
@Bean public PersonService personService(){ return new PersonService("arg"); }}
public PersonService { public PersonService(String arg) { // обычный конструктор } // обычные методы}
Есть класс с конфигурацией @Configuration.
@Bean помечены методы (!)которые возвращают бины.
Фактически бины создаются обычным Java-кодом.
www.luxoft.com 22
Java-based конфигурация (+)@Configurationpublic class ApplicationConfig {
@Bean public PersonService personService(){ return new PersonService("arg"); }}
public PersonService { public PersonService(String arg) { // обычный конструктор } // обычные методы}
Никакого XML, только Java. Явное создание и
настройка. Type-safe. Некоторые ошибки стали
compile-time. Обычный рефакторинг.
www.luxoft.com 23
Java-based конфигурация (+)@Configurationpublic class ApplicationConfig {
@Bean public PersonService personService(){ return new PersonService("arg"); }}
public PersonService { public PersonService(String arg) { // обычный конструктор } // обычные методы}
Smart-подсказки работают.
Позволяют отделить Domain от Spring.
Современно.
www.luxoft.com 24
Java-based конфигурация (–)@Configurationpublic class ApplicationConfig {
@Bean public PersonService personService(){ return new PersonService("arg"); }}
public PersonService { public PersonService(String arg) { // обычный конструктор } // обычные методы}
Возможно смешение бизнес-и конфигурационной логики.
Java-кода иногда нужно больше.
Требует некоторой дисциплины для разарботчиков.
С Java-based конфигурации проще начинать, чем на неё переходить.
www.luxoft.com 25
Почему так получается? Что делать?
Смешение бизнес- и конфигурационной логики? Конфигурацию вынести в отдельный пакет/модуль. Договорённости, ревью.
Большие классы конфигурации? Используйте @Import: классы делятся проще и естественнее,
чем XML. Начинайте со Spring Boot.
www.luxoft.com 26
Spring Boot
www.luxoft.com 27
Spring Boot
Spring Framework Spring Boot
www.luxoft.com 28
Spring Boot
Предназначен для мексимально быстрой разработки.
Сразу доступны общие features. Автоматически конфигурирует
компоненты. По-умолчанию использует Java-
based конфигурацию. Возможности для тетсирования
всего микросервиса.
www.luxoft.com 29
Spring Boot
www.luxoft.com 30
Conditional
Если класс присутсвует в classpath – тогда создаётся бин.
Включается @EnableAutoConfiguration
@Configurationpublic class AppConfig { @Bean @Conditional( MySQLDatabaseTypeCondition.class ) public UserDAO jdbcUserDAO() { return new JdbcUserDAO(); }
@Bean @Conditional( MongoDBDatabaseTypeCondition.class ) public UserDAO mongoUserDAO() { return new MongoUserDAO(); }
}
www.luxoft.com 31
Auto configurations
spring-boot-starter-* spring-boot-starter-aop spring-boot-starter-jdbc spring-boot-starter-mvc spring-boot-strater-tx ...
spring.datasource.driverClassName =org.postgresql.Driver
spring.datasource.url =jdbc:postgresql://srv0/test
spring.datasource.username =test
spring.datasource.password =test
www.luxoft.com 32
Properties
#application.properties
my.app.title=Пример
// UTF-8
#application.properties
my.app.title=
// ISO-8859-1
www.luxoft.com 33
Properties
properties.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Hi</comment>
<entry key="foo">bar</entry>
<entry key="fu">baz</entry>
</properties>
www.luxoft.com 34
Properties
#app.properties
environments.dev.url =http://dev.bar.com
environments.dev.name =Developer Setup
environments.prod.url =http://foo.bar.com
environments.prod.name =My Cool App
#app.yaml
environments:
dev:
url: http://dev.bar.com
name: Developer Setup
prod:
url: http://foo.bar.com
name: My Cool App
www.luxoft.com 35
Properties
Куда их класть: jar/war /var/lib/tomcat/conf /etc/luxoft/sampleapp/app.yaml в git-репозиторий? в системные свойства (можно
туда класть JSON) параметры запуска git!
Откуда брать? Из системых свойств Из пареметров запуска Из файла в широком сымсле С сервера в широком
смысле git файл на сервере Ваш собственный config server
www.luxoft.com 36
Config server Config server Client@EnableConfigServer
spring.platform.config.server.uri: https://github.com/config-repo
<dependency> <groupId> org.springframework.cloud </groupId> <artifactId> spring-cloud-config-server </artifactId> </dependency>
spring.cloud.config.uri: http://myconfigserver.com
<dependency> <groupId> org.springframework.cloud </groupId> <artifactId> spring-cloud-config-client </artifactId> </dependency><dependency> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-starter-actuator </artifactId> </dependency>
www.luxoft.com 37
Properties
Жизнь с config-server правим настройки собираем новую версию останавливаем каждую
ноду обновляем каждую ноды запускаем заново
Жизнь с config-server правим настройки (git) перезапускаем config-
server перезапускаем ноды по
одной
www.luxoft.com 38
spring-cloud config server
http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html
www.luxoft.com
Спасибо за внимание!
Вопросы?