39
www.luxoft.com Конфигурирование Spring-приложений Дворжецкий Юрий 25 июня 2016

DEV Labs 2016. Конфигурирование spring-приложений

Embed Size (px)

Citation preview

Page 1: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com

КонфигурированиеSpring-приложений

Дворжецкий Юрий

25 июня 2016

Page 2: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 2

О чём доклад?

XML-based конфигурация:­ Почему так плохо получается?­ Что делать?

Annotation-based:­ Почему так плохо получается?­ Что делать?

Java-based конфигурация:­ Почему так плохо получается?­ Что делать?

Конфигурировние вместе со Spring Boot.

Properties – куда их класть и откуда брать?

Немного Spring Cloud.

Page 3: DEV Labs 2016. Конфигурирование spring-приложений

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..

Page 4: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 4

XML-based конфигурация (+)

Всем знакома. Большая часть

документации и примеров с XML.

Централизованная конфигурация.

Естественно уменьшает связАнность Java-кода.

Page 5: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 5

XML-based конфигурация (–)

Огромные XML. XML. Необходимость изменять

в нескольких местах. Тяжело рефакторить. Не всегда работают Smart

* Ошибки в run-time.

Page 6: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 6

Почему так получается? Что делать?

Огромные XML:­ <import /> – позволяет из

одной большой XML сделать несколько маленьких.

­ Делить приложение на модули.

<import resource= "classpath*:context.xml"/>

Page 7: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 7

Почему так получается? Что делать?

Огромные XML - используйте расширения:­ util­ mvc­ tx­ security­ context

<util:properties location="my.properties"/>

Page 8: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 8

Почему так получается? Что делать?

Огромные XML - используйте Spring Expression Language:­ для выражений,

касающихся конфигурации;­ не для бизнес-логики.

<bean id="bean1"></bean><bean> <property ref="bean1"/></bean>

<!-- SpEL -->

<property value="#{new My()}"/>

Page 9: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 9

Почему так получается? Что делать?

Огромные XML? Много связей? Хочется auto-wiring?

<bean id="bean1"> ...</bean>

<bean autowire="byType"></bean>

Page 10: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 10

Почему так получается? Что делать?

Ошибки в run-time (run-time бывает разный)­ Используйте, по возможности,

<constructor-arg> вместо <property>.­ Поднимается ли контекст || часть контекста, можно

протестироватьв Unit-тестах.

Page 11: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 11

XML

Жизнь с XML Жизнь без XML

Page 12: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 12

Annotation-based конфигурация

public class MovieRecommender { @Autowired MovieCatalog movieCatalog;

// отсутствующий конструктор // отсутствующие сеттеры // ...}

@Servicepublic MovieCatalog { // ...}

Активно используется @Autowired

Стереотипы:­ @Controller / @RestController­ @Service, ...

@Value("${my.property}")

Page 13: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 13

Annotation-based конфигурация (+)

public class MovieRecommender { @Autowired MovieCatalog movieCatalog;

// отсутствующий конструктор // отсутствующие сеттеры // ...}

@Servicepublic MovieCatalog { // ...}

Никакого XML (или почти). Изменения в одном месте. Меньше Java-кода. Рефакторинг стал проще. Некоторые run-time ошибки

просто исчезли. spring-mvc, spring-* так и

используют.

Page 14: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 14

Annotation-based конфигурация (–)

Иногда нужно несколько бинов одного класса.

С @Autowired полями тяжелее пишутся Unit-тесты.

Добавить зависимость – элементарно.

public class MovieRecommender { @Autowired MovieCatalog movieCatalog;

// отсутствующий конструктор // отсутствующие сеттеры // ...}

@Servicepublic MovieCatalog { // ...}

Page 15: DEV Labs 2016. Конфигурирование spring-приложений

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;}

Page 16: DEV Labs 2016. Конфигурирование spring-приложений

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;}

Page 17: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 17

Annotation-based конфигурация (–)

View

Domain

Data Source

DB

Infra

stru

ctur

e

Page 18: DEV Labs 2016. Конфигурирование spring-приложений

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

Page 19: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 19

Как не использовать Spring в Domain?

DB

View

DS

Domain

Infrastructure

Page 20: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 20

А где файл c бинами контекста?

Непонятно куда размещать чисто конфигурационный код.

С аннотациями @Component, @Service проблематично создать несколько бинов одного класса.

Сторонние классы без этих аннотаций.

Уменьшить связАннось.

Page 21: DEV Labs 2016. Конфигурирование spring-приложений

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-кодом.

Page 22: DEV Labs 2016. Конфигурирование spring-приложений

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. Обычный рефакторинг.

Page 23: DEV Labs 2016. Конфигурирование spring-приложений

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.

Современно.

Page 24: DEV Labs 2016. Конфигурирование 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 конфигурации проще начинать, чем на неё переходить.

Page 25: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 25

Почему так получается? Что делать?

Смешение бизнес- и конфигурационной логики?­ Конфигурацию вынести в отдельный пакет/модуль.­ Договорённости, ревью.

Большие классы конфигурации?­ Используйте @Import: классы делятся проще и естественнее,

чем XML.­ Начинайте со Spring Boot.

Page 26: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 26

Spring Boot

Page 27: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 27

Spring Boot

Spring Framework Spring Boot

Page 28: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 28

Spring Boot

Предназначен для мексимально быстрой разработки.

Сразу доступны общие features. Автоматически конфигурирует

компоненты. По-умолчанию использует Java-

based конфигурацию. Возможности для тетсирования

всего микросервиса.

Page 29: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 29

Spring Boot

Page 30: DEV Labs 2016. Конфигурирование spring-приложений

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(); }

}

Page 31: DEV Labs 2016. Конфигурирование spring-приложений

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

Page 32: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 32

Properties

#application.properties

my.app.title=Пример

// UTF-8

#application.properties

my.app.title=

// ISO-8859-1

Page 33: DEV Labs 2016. Конфигурирование spring-приложений

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>

Page 34: DEV Labs 2016. Конфигурирование spring-приложений

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

Page 35: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 35

Properties

Куда их класть:­ jar/war­ /var/lib/tomcat/conf­ /etc/luxoft/sampleapp/app.yaml­ в git-репозиторий?­ в системные свойства (можно

туда класть JSON)­ параметры запуска­ git!

Откуда брать?­ Из системых свойств­ Из пареметров запуска­ Из файла в широком сымсле­ С сервера в широком

смысле git файл на сервере Ваш собственный config server

Page 36: DEV Labs 2016. Конфигурирование spring-приложений

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>

Page 37: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com 37

Properties

Жизнь с config-server правим настройки собираем новую версию останавливаем каждую

ноду обновляем каждую ноды запускаем заново

Жизнь с config-server правим настройки (git) перезапускаем config-

server перезапускаем ноды по

одной

Page 39: DEV Labs 2016. Конфигурирование spring-приложений

www.luxoft.com

Спасибо за внимание!

Вопросы?